From: Matthias Clasen Date: Tue, 4 Oct 2022 01:54:57 +0000 (-0400) Subject: Deprecate the app chooser widgets X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~116^2~1^2~211^2 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=a527a4d82ede02019b30626a89ca9775da22d382;p=gtk4.git Deprecate the app chooser widgets These are a family of pretty specialized widgets, and are very rarely used. Instead of porting them away from GtkTreeView and GtkComboBox, deprecate them. --- diff --git a/demos/gtk-demo/pickers.c b/demos/gtk-demo/pickers.c index 05d831221f..1ecd9a3adf 100644 --- a/demos/gtk-demo/pickers.c +++ b/demos/gtk-demo/pickers.c @@ -123,8 +123,14 @@ do_pickers (GtkWidget *do_widget) gtk_widget_set_halign (label, GTK_ALIGN_START); gtk_widget_set_valign (label, GTK_ALIGN_CENTER); gtk_widget_set_hexpand (label, TRUE); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + picker = gtk_app_chooser_button_new ("x-scheme-handler/mailto"); gtk_app_chooser_button_set_show_dialog_item (GTK_APP_CHOOSER_BUTTON (picker), TRUE); + +G_GNUC_END_IGNORE_DEPRECATIONS + gtk_grid_attach (GTK_GRID (table), label, 0, 3, 1, 1); gtk_grid_attach (GTK_GRID (table), picker, 1, 3, 1, 1); } diff --git a/gtk/deprecated/gtkappchooser.c b/gtk/deprecated/gtkappchooser.c new file mode 100644 index 0000000000..db2e9fecba --- /dev/null +++ b/gtk/deprecated/gtkappchooser.c @@ -0,0 +1,133 @@ +/* + * gtkappchooser.c: app-chooser interface + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Cosimo Cecchi + */ + +/** + * GtkAppChooser: + * + * `GtkAppChooser` is an interface for widgets which allow the user to + * choose an application. + * + * The main objects that implement this interface are + * [class@Gtk.AppChooserWidget], + * [class@Gtk.AppChooserDialog] and [class@Gtk.AppChooserButton]. + * + * Applications are represented by GIO `GAppInfo` objects here. + * GIO has a concept of recommended and fallback applications for a + * given content type. Recommended applications are those that claim + * to handle the content type itself, while fallback also includes + * applications that handle a more generic content type. GIO also + * knows the default and last-used application for a given content + * type. The `GtkAppChooserWidget` provides detailed control over + * whether the shown list of applications should include default, + * recommended or fallback applications. + * + * To obtain the application that has been selected in a `GtkAppChooser`, + * use [method@Gtk.AppChooser.get_app_info]. + */ + +#include "config.h" + +#include "gtkappchooser.h" + +#include "gtkappchooserprivate.h" +#include "gtkwidget.h" + +#include + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +G_DEFINE_INTERFACE (GtkAppChooser, gtk_app_chooser, GTK_TYPE_WIDGET); + +static void +gtk_app_chooser_default_init (GtkAppChooserIface *iface) +{ + GParamSpec *pspec; + + /** + * GtkAppChooser:content-type: (attributes org.gtk.Property.get=gtk_app_chooser_get_content_type) + * + * The content type of the `GtkAppChooser` object. + * + * See `GContentType` for more information about content types. + */ + pspec = g_param_spec_string ("content-type", NULL, NULL, + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_interface_install_property (iface, pspec); +} + + +/** + * gtk_app_chooser_get_content_type: (attributes org.gtk.Method.get_property=content-type) + * @self: a `GtkAppChooser` + * + * Returns the content type for which the `GtkAppChooser` + * shows applications. + * + * Returns: the content type of @self. Free with g_free() + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +char * +gtk_app_chooser_get_content_type (GtkAppChooser *self) +{ + char *retval = NULL; + + g_return_val_if_fail (GTK_IS_APP_CHOOSER (self), NULL); + + g_object_get (self, + "content-type", &retval, + NULL); + + return retval; +} + +/** + * gtk_app_chooser_get_app_info: + * @self: a `GtkAppChooser` + * + * Returns the currently selected application. + * + * Returns: (nullable) (transfer full): a `GAppInfo` for the + * currently selected application + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +GAppInfo * +gtk_app_chooser_get_app_info (GtkAppChooser *self) +{ + return GTK_APP_CHOOSER_GET_IFACE (self)->get_app_info (self); +} + +/** + * gtk_app_chooser_refresh: + * @self: a `GtkAppChooser` + * + * Reloads the list of applications. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_refresh (GtkAppChooser *self) +{ + GTK_APP_CHOOSER_GET_IFACE (self)->refresh (self); +} diff --git a/gtk/deprecated/gtkappchooser.h b/gtk/deprecated/gtkappchooser.h new file mode 100644 index 0000000000..4c928a08f0 --- /dev/null +++ b/gtk/deprecated/gtkappchooser.h @@ -0,0 +1,56 @@ +/* + * gtkappchooser.h: app-chooser interface + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Cosimo Cecchi + */ + +#ifndef __GTK_APP_CHOOSER_H__ +#define __GTK_APP_CHOOSER_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_APP_CHOOSER (gtk_app_chooser_get_type ()) +#define GTK_APP_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER, GtkAppChooser)) +#define GTK_IS_APP_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER)) + +typedef struct _GtkAppChooser GtkAppChooser; + +GDK_AVAILABLE_IN_ALL +GType gtk_app_chooser_get_type (void) G_GNUC_CONST; + +GDK_DEPRECATED_IN_4_10 +GAppInfo * gtk_app_chooser_get_app_info (GtkAppChooser *self); +GDK_DEPRECATED_IN_4_10 +char * gtk_app_chooser_get_content_type (GtkAppChooser *self); +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_refresh (GtkAppChooser *self); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooser, g_object_unref) + +G_END_DECLS + +#endif /* __GTK_APP_CHOOSER_H__ */ + diff --git a/gtk/deprecated/gtkappchooserbutton.c b/gtk/deprecated/gtkappchooserbutton.c new file mode 100644 index 0000000000..6a5044fbdd --- /dev/null +++ b/gtk/deprecated/gtkappchooserbutton.c @@ -0,0 +1,1158 @@ +/* gtkappchooserbutton.c: an app-chooser button + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Cosimo Cecchi + */ + +/** + * GtkAppChooserButton: + * + * The `GtkAppChooserButton` lets the user select an application. + * + * ![An example GtkAppChooserButton](appchooserbutton.png) + * + * Initially, a `GtkAppChooserButton` selects the first application + * in its list, which will either be the most-recently used application + * or, if [property@Gtk.AppChooserButton:show-default-item] is %TRUE, the + * default application. + * + * The list of applications shown in a `GtkAppChooserButton` includes + * the recommended applications for the given content type. When + * [property@Gtk.AppChooserButton:show-default-item] is set, the default + * application is also included. To let the user chooser other applications, + * you can set the [property@Gtk.AppChooserButton:show-dialog-item] property, + * which allows to open a full [class@Gtk.AppChooserDialog]. + * + * It is possible to add custom items to the list, using + * [method@Gtk.AppChooserButton.append_custom_item]. These items cause + * the [signal@Gtk.AppChooserButton::custom-item-activated] signal to be + * emitted when they are selected. + * + * To track changes in the selected application, use the + * [signal@Gtk.AppChooserButton::changed] signal. + * + * # CSS nodes + * + * `GtkAppChooserButton` has a single CSS node with the name “appchooserbutton”. + */ +#include "config.h" + +#include "gtkappchooserbutton.h" + +#include "gtkappchooser.h" +#include "gtkappchooserdialog.h" +#include "gtkappchooserprivate.h" +#include "gtkcelllayout.h" +#include "gtkcellrendererpixbuf.h" +#include "gtkcellrenderertext.h" +#include "gtkcombobox.h" +#include "gtkwidgetprivate.h" +#include "gtkdialog.h" +#include +#include "gtkmarshalers.h" +#include "gtkliststore.h" +#include "gtkprivate.h" + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +enum { + PROP_SHOW_DIALOG_ITEM = 1, + PROP_SHOW_DEFAULT_ITEM, + PROP_HEADING, + PROP_MODAL, + NUM_PROPERTIES, + + PROP_CONTENT_TYPE = NUM_PROPERTIES +}; + +enum { + SIGNAL_CHANGED, + SIGNAL_CUSTOM_ITEM_ACTIVATED, + ACTIVATE, + NUM_SIGNALS +}; + +enum { + COLUMN_APP_INFO, + COLUMN_NAME, + COLUMN_LABEL, + COLUMN_ICON, + COLUMN_CUSTOM, + COLUMN_SEPARATOR, + NUM_COLUMNS, +}; + +#define CUSTOM_ITEM_OTHER_APP "gtk-internal-item-other-app" + +static void app_chooser_iface_init (GtkAppChooserIface *iface); + +static void real_insert_custom_item (GtkAppChooserButton *self, + const char *name, + const char *label, + GIcon *icon, + gboolean custom, + GtkTreeIter *iter); + +static void real_insert_separator (GtkAppChooserButton *self, + gboolean custom, + GtkTreeIter *iter); + +static guint signals[NUM_SIGNALS] = { 0, }; +static GParamSpec *properties[NUM_PROPERTIES]; + +typedef struct _GtkAppChooserButtonClass GtkAppChooserButtonClass; + +struct _GtkAppChooserButton { + GtkWidget parent_instance; + + GtkWidget *combobox; + GtkListStore *store; + + char *content_type; + char *heading; + int last_active; + gboolean show_dialog_item; + gboolean show_default_item; + gboolean modal; + + GHashTable *custom_item_names; +}; + +struct _GtkAppChooserButtonClass { + GtkWidgetClass parent_class; + + void (* changed) (GtkAppChooserButton *self); + void (* custom_item_activated) (GtkAppChooserButton *self, + const char *item_name); + void (* activate) (GtkAppChooserButton *self); +}; + +G_DEFINE_TYPE_WITH_CODE (GtkAppChooserButton, gtk_app_chooser_button, GTK_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER, + app_chooser_iface_init)); + +static gboolean +row_separator_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + gboolean separator; + + gtk_tree_model_get (model, iter, + COLUMN_SEPARATOR, &separator, + -1); + + return separator; +} + +static void +get_first_iter (GtkListStore *store, + GtkTreeIter *iter) +{ + GtkTreeIter iter2; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), iter)) + { + /* the model is empty, append */ + gtk_list_store_append (store, iter); + } + else + { + gtk_list_store_insert_before (store, &iter2, iter); + *iter = iter2; + } +} + +typedef struct { + GtkAppChooserButton *self; + GAppInfo *info; + int active_index; +} SelectAppData; + +static void +select_app_data_free (SelectAppData *data) +{ + g_clear_object (&data->self); + g_clear_object (&data->info); + + g_slice_free (SelectAppData, data); +} + +static gboolean +select_application_func_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + SelectAppData *data = user_data; + GtkAppChooserButton *self = data->self; + GAppInfo *app_to_match = data->info; + GAppInfo *app = NULL; + gboolean custom; + gboolean result; + + gtk_tree_model_get (model, iter, + COLUMN_APP_INFO, &app, + COLUMN_CUSTOM, &custom, + -1); + + /* custom items are always after GAppInfos, so iterating further here + * is just useless. + */ + if (custom) + result = TRUE; + else if (g_app_info_equal (app, app_to_match)) + { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), iter); + result = TRUE; + } + else + result = FALSE; + + g_object_unref (app); + + return result; +} + +static void +gtk_app_chooser_button_select_application (GtkAppChooserButton *self, + GAppInfo *info) +{ + SelectAppData *data; + + data = g_slice_new0 (SelectAppData); + data->self = g_object_ref (self); + data->info = g_object_ref (info); + + gtk_tree_model_foreach (GTK_TREE_MODEL (self->store), + select_application_func_cb, data); + + select_app_data_free (data); +} + +static void +other_application_dialog_response_cb (GtkDialog *dialog, + int response_id, + gpointer user_data) +{ + GtkAppChooserButton *self = user_data; + GAppInfo *info; + + if (response_id != GTK_RESPONSE_OK) + { + /* reset the active item, otherwise we are stuck on + * 'Other application…' + */ + gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), self->last_active); + gtk_window_destroy (GTK_WINDOW (dialog)); + return; + } + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog)); + + gtk_window_destroy (GTK_WINDOW (dialog)); + + /* refresh the combobox to get the new application */ + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + gtk_app_chooser_button_select_application (self, info); + + g_object_unref (info); +} + +static void +other_application_item_activated_cb (GtkAppChooserButton *self) +{ + GtkWidget *dialog, *widget; + GtkRoot *root; + + root = gtk_widget_get_root (GTK_WIDGET (self)); + dialog = gtk_app_chooser_dialog_new_for_content_type (GTK_WINDOW (root), + GTK_DIALOG_DESTROY_WITH_PARENT, + self->content_type); + gtk_window_set_modal (GTK_WINDOW (dialog), self->modal | gtk_window_get_modal (GTK_WINDOW (root))); + gtk_app_chooser_dialog_set_heading (GTK_APP_CHOOSER_DIALOG (dialog), self->heading); + + widget = gtk_app_chooser_dialog_get_widget (GTK_APP_CHOOSER_DIALOG (dialog)); + g_object_set (widget, + "show-fallback", TRUE, + "show-other", TRUE, + NULL); + gtk_widget_show (dialog); + + g_signal_connect (dialog, "response", + G_CALLBACK (other_application_dialog_response_cb), self); +} + +static void +gtk_app_chooser_button_ensure_dialog_item (GtkAppChooserButton *self, + GtkTreeIter *prev_iter) +{ + GtkTreeIter iter, iter2; + + if (!self->show_dialog_item || !self->content_type) + return; + + if (prev_iter == NULL) + gtk_list_store_append (self->store, &iter); + else + gtk_list_store_insert_after (self->store, &iter, prev_iter); + + real_insert_separator (self, FALSE, &iter); + iter2 = iter; + + gtk_list_store_insert_after (self->store, &iter, &iter2); + real_insert_custom_item (self, CUSTOM_ITEM_OTHER_APP, + _("Other application…"), NULL, + FALSE, &iter); +} + +static void +insert_one_application (GtkAppChooserButton *self, + GAppInfo *app, + GtkTreeIter *iter) +{ + GIcon *icon; + + icon = g_app_info_get_icon (app); + + if (icon == NULL) + icon = g_themed_icon_new ("application-x-executable"); + else + g_object_ref (icon); + + gtk_list_store_set (self->store, iter, + COLUMN_APP_INFO, app, + COLUMN_LABEL, g_app_info_get_name (app), + COLUMN_ICON, icon, + COLUMN_CUSTOM, FALSE, + -1); + + g_object_unref (icon); +} + +static void +gtk_app_chooser_button_populate (GtkAppChooserButton *self) +{ + GList *recommended_apps = NULL, *l; + GAppInfo *app, *default_app = NULL; + GtkTreeIter iter, iter2; + gboolean cycled_recommended; + +#ifndef G_OS_WIN32 + if (self->content_type) + recommended_apps = g_app_info_get_recommended_for_type (self->content_type); +#endif + cycled_recommended = FALSE; + + if (self->show_default_item) + { + if (self->content_type) + default_app = g_app_info_get_default_for_type (self->content_type, FALSE); + + if (default_app != NULL) + { + get_first_iter (self->store, &iter); + cycled_recommended = TRUE; + + insert_one_application (self, default_app, &iter); + + g_object_unref (default_app); + } + } + + for (l = recommended_apps; l != NULL; l = l->next) + { + app = l->data; + + if (default_app != NULL && g_app_info_equal (app, default_app)) + continue; + + if (cycled_recommended) + { + gtk_list_store_insert_after (self->store, &iter2, &iter); + iter = iter2; + } + else + { + get_first_iter (self->store, &iter); + cycled_recommended = TRUE; + } + + insert_one_application (self, app, &iter); + } + + if (recommended_apps != NULL) + g_list_free_full (recommended_apps, g_object_unref); + + if (!cycled_recommended) + gtk_app_chooser_button_ensure_dialog_item (self, NULL); + else + gtk_app_chooser_button_ensure_dialog_item (self, &iter); + + gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), 0); +} + +static void +gtk_app_chooser_button_build_ui (GtkAppChooserButton *self) +{ + GtkCellRenderer *cell; + GtkCellArea *area; + + gtk_combo_box_set_model (GTK_COMBO_BOX (self->combobox), + GTK_TREE_MODEL (self->store)); + + area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (self->combobox)); + + gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (self->combobox), + row_separator_func, NULL, NULL); + + cell = gtk_cell_renderer_pixbuf_new (); + gtk_cell_area_add_with_properties (area, cell, + "align", FALSE, + "expand", FALSE, + "fixed-size", FALSE, + NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell, + "gicon", COLUMN_ICON, + NULL); + + cell = gtk_cell_renderer_text_new (); + gtk_cell_area_add_with_properties (area, cell, + "align", FALSE, + "expand", TRUE, + NULL); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell, + "text", COLUMN_LABEL, + NULL); + + gtk_app_chooser_button_populate (self); +} + +static void +gtk_app_chooser_button_remove_non_custom (GtkAppChooserButton *self) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean custom, res; + + model = GTK_TREE_MODEL (self->store); + + if (!gtk_tree_model_get_iter_first (model, &iter)) + return; + + do { + gtk_tree_model_get (model, &iter, + COLUMN_CUSTOM, &custom, + -1); + if (custom) + res = gtk_tree_model_iter_next (model, &iter); + else + res = gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + } while (res); +} + +static void +gtk_app_chooser_button_changed (GtkComboBox *object, + gpointer user_data) +{ + GtkAppChooserButton *self = user_data; + GtkTreeIter iter; + char *name = NULL; + gboolean custom; + GQuark name_quark; + + if (!gtk_combo_box_get_active_iter (object, &iter)) + return; + + gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter, + COLUMN_NAME, &name, + COLUMN_CUSTOM, &custom, + -1); + + if (name != NULL) + { + if (custom) + { + name_quark = g_quark_from_string (name); + g_signal_emit (self, signals[SIGNAL_CUSTOM_ITEM_ACTIVATED], name_quark, name); + self->last_active = gtk_combo_box_get_active (object); + } + else + { + /* trigger the dialog internally */ + other_application_item_activated_cb (self); + } + + g_free (name); + } + else + self->last_active = gtk_combo_box_get_active (object); + + g_signal_emit (self, signals[SIGNAL_CHANGED], 0); +} + +static void +gtk_app_chooser_button_refresh (GtkAppChooser *object) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object); + + gtk_app_chooser_button_remove_non_custom (self); + gtk_app_chooser_button_populate (self); +} + +static GAppInfo * +gtk_app_chooser_button_get_app_info (GtkAppChooser *object) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object); + GtkTreeIter iter; + GAppInfo *info; + + if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->combobox), &iter)) + return NULL; + + gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter, + COLUMN_APP_INFO, &info, + -1); + + return info; +} + +static void +gtk_app_chooser_button_constructed (GObject *obj) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); + + if (G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed != NULL) + G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed (obj); + + gtk_app_chooser_button_build_ui (self); +} + +static void +gtk_app_chooser_button_set_property (GObject *obj, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); + + switch (property_id) + { + case PROP_CONTENT_TYPE: + self->content_type = g_value_dup_string (value); + break; + case PROP_SHOW_DIALOG_ITEM: + gtk_app_chooser_button_set_show_dialog_item (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_DEFAULT_ITEM: + gtk_app_chooser_button_set_show_default_item (self, g_value_get_boolean (value)); + break; + case PROP_HEADING: + gtk_app_chooser_button_set_heading (self, g_value_get_string (value)); + break; + case PROP_MODAL: + gtk_app_chooser_button_set_modal (self, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); + break; + } +} + +static void +gtk_app_chooser_button_get_property (GObject *obj, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); + + switch (property_id) + { + case PROP_CONTENT_TYPE: + g_value_set_string (value, self->content_type); + break; + case PROP_SHOW_DIALOG_ITEM: + g_value_set_boolean (value, self->show_dialog_item); + break; + case PROP_SHOW_DEFAULT_ITEM: + g_value_set_boolean (value, self->show_default_item); + break; + case PROP_HEADING: + g_value_set_string (value, self->heading); + break; + case PROP_MODAL: + g_value_set_boolean (value, self->modal); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); + break; + } +} + +static void +gtk_app_chooser_button_finalize (GObject *obj) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); + + g_hash_table_destroy (self->custom_item_names); + g_free (self->content_type); + g_free (self->heading); + g_object_unref (self->store); + gtk_widget_unparent (self->combobox); + + G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->finalize (obj); +} + +static void +gtk_app_chooser_button_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget); + + gtk_widget_measure (self->combobox, orientation, for_size, + minimum, natural, + minimum_baseline, natural_baseline); +} + +static void +gtk_app_chooser_button_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget); + + gtk_widget_size_allocate (self->combobox, &(GtkAllocation){0, 0, width, height}, baseline); +} + +static void +app_chooser_iface_init (GtkAppChooserIface *iface) +{ + iface->get_app_info = gtk_app_chooser_button_get_app_info; + iface->refresh = gtk_app_chooser_button_refresh; +} + +static void +gtk_app_chooser_button_activate (GtkAppChooserButton *self) +{ + gtk_widget_activate (self->combobox); +} + +static void +gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + oclass->set_property = gtk_app_chooser_button_set_property; + oclass->get_property = gtk_app_chooser_button_get_property; + oclass->finalize = gtk_app_chooser_button_finalize; + oclass->constructed = gtk_app_chooser_button_constructed; + + widget_class->measure = gtk_app_chooser_button_measure; + widget_class->size_allocate = gtk_app_chooser_button_size_allocate; + widget_class->grab_focus = gtk_widget_grab_focus_child; + widget_class->focus = gtk_widget_focus_child; + + klass->activate = gtk_app_chooser_button_activate; + + g_object_class_override_property (oclass, PROP_CONTENT_TYPE, "content-type"); + + /** + * GtkAppChooserButton:show-dialog-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_dialog_item org.gtk.Property.set=gtk_app_chooser_button_set_show_dialog_item) + * + * Determines whether the dropdown menu shows an item to open + * a `GtkAppChooserDialog`. + */ + properties[PROP_SHOW_DIALOG_ITEM] = + g_param_spec_boolean ("show-dialog-item", NULL, NULL, + FALSE, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkAppChooserButton:show-default-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_default_item org.gtk.Property.set=gtk_app_chooser_button_set_show_default_item) + * + * Determines whether the dropdown menu shows the default application + * on top for the provided content type. + */ + properties[PROP_SHOW_DEFAULT_ITEM] = + g_param_spec_boolean ("show-default-item", NULL, NULL, + FALSE, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkAppChooserButton:heading: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_heading org.gtk.Property.set=gtk_app_chooser_button_set_heading) + * + * The text to show at the top of the dialog that can be + * opened from the button. + * + * The string may contain Pango markup. + */ + properties[PROP_HEADING] = + g_param_spec_string ("heading", NULL, NULL, + NULL, + G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); + + /** + * GtkAppChooserButton:modal: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_modal org.gtk.Property.set=gtk_app_chooser_button_set_modal) + * + * Whether the app chooser dialog should be modal. + */ + properties[PROP_MODAL] = + g_param_spec_boolean ("modal", NULL, NULL, + TRUE, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); + + /** + * GtkAppChooserButton::changed: + * @self: the object which received the signal + * + * Emitted when the active application changes. + */ + signals[SIGNAL_CHANGED] = + g_signal_new (I_("changed"), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAppChooserButtonClass, changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + + /** + * GtkAppChooserButton::custom-item-activated: + * @self: the object which received the signal + * @item_name: the name of the activated item + * + * Emitted when a custom item is activated. + * + * Use [method@Gtk.AppChooserButton.append_custom_item], + * to add custom items. + */ + signals[SIGNAL_CUSTOM_ITEM_ACTIVATED] = + g_signal_new (I_("custom-item-activated"), + GTK_TYPE_APP_CHOOSER_BUTTON, + G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, + G_STRUCT_OFFSET (GtkAppChooserButtonClass, custom_item_activated), + NULL, NULL, + NULL, + G_TYPE_NONE, + 1, G_TYPE_STRING); + + /** + * GtkAppChooserButton::activate: + * @widget: the object which received the signal. + * + * Emitted to when the button is activated. + * + * The `::activate` signal on `GtkAppChooserButton` is an action signal and + * emitting it causes the button to pop up its dialog. + * + * Since: 4.4 + */ + signals[ACTIVATE] = + g_signal_new (I_ ("activate"), + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkAppChooserButtonClass, activate), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE]); + + + gtk_widget_class_set_css_name (widget_class, I_("appchooserbutton")); +} + +static void +gtk_app_chooser_button_init (GtkAppChooserButton *self) +{ + self->modal = TRUE; + + self->custom_item_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + self->store = gtk_list_store_new (NUM_COLUMNS, + G_TYPE_APP_INFO, + G_TYPE_STRING, /* name */ + G_TYPE_STRING, /* label */ + G_TYPE_ICON, + G_TYPE_BOOLEAN, /* separator */ + G_TYPE_BOOLEAN); /* custom */ + self->combobox = gtk_combo_box_new_with_model (GTK_TREE_MODEL (self->store)); + gtk_widget_set_parent (self->combobox, GTK_WIDGET (self)); + + g_signal_connect (self->combobox, "changed", + G_CALLBACK (gtk_app_chooser_button_changed), self); +} + +static gboolean +app_chooser_button_iter_from_custom_name (GtkAppChooserButton *self, + const char *name, + GtkTreeIter *set_me) +{ + GtkTreeIter iter; + char *custom_name = NULL; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter)) + return FALSE; + + do { + gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter, + COLUMN_NAME, &custom_name, + -1); + + if (g_strcmp0 (custom_name, name) == 0) + { + g_free (custom_name); + *set_me = iter; + + return TRUE; + } + + g_free (custom_name); + } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter)); + + return FALSE; +} + +static void +real_insert_custom_item (GtkAppChooserButton *self, + const char *name, + const char *label, + GIcon *icon, + gboolean custom, + GtkTreeIter *iter) +{ + if (custom) + { + if (g_hash_table_lookup (self->custom_item_names, name) != NULL) + { + g_warning ("Attempting to add custom item %s to GtkAppChooserButton, " + "when there's already an item with the same name", name); + return; + } + + g_hash_table_insert (self->custom_item_names, + g_strdup (name), GINT_TO_POINTER (1)); + } + + gtk_list_store_set (self->store, iter, + COLUMN_NAME, name, + COLUMN_LABEL, label, + COLUMN_ICON, icon, + COLUMN_CUSTOM, custom, + COLUMN_SEPARATOR, FALSE, + -1); +} + +static void +real_insert_separator (GtkAppChooserButton *self, + gboolean custom, + GtkTreeIter *iter) +{ + gtk_list_store_set (self->store, iter, + COLUMN_CUSTOM, custom, + COLUMN_SEPARATOR, TRUE, + -1); +} + +/** + * gtk_app_chooser_button_new: + * @content_type: the content type to show applications for + * + * Creates a new `GtkAppChooserButton` for applications + * that can handle content of the given type. + * + * Returns: a newly created `GtkAppChooserButton` + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +GtkWidget * +gtk_app_chooser_button_new (const char *content_type) +{ + g_return_val_if_fail (content_type != NULL, NULL); + + return g_object_new (GTK_TYPE_APP_CHOOSER_BUTTON, + "content-type", content_type, + NULL); +} + +/** + * gtk_app_chooser_button_append_separator: + * @self: a `GtkAppChooserButton` + * + * Appends a separator to the list of applications that is shown + * in the popup. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_button_append_separator (GtkAppChooserButton *self) +{ + GtkTreeIter iter; + + g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); + + gtk_list_store_append (self->store, &iter); + real_insert_separator (self, TRUE, &iter); +} + +/** + * gtk_app_chooser_button_append_custom_item: + * @self: a `GtkAppChooserButton` + * @name: the name of the custom item + * @label: the label for the custom item + * @icon: the icon for the custom item + * + * Appends a custom item to the list of applications that is shown + * in the popup. + * + * The item name must be unique per-widget. Clients can use the + * provided name as a detail for the + * [signal@Gtk.AppChooserButton::custom-item-activated] signal, to add a + * callback for the activation of a particular custom item in the list. + * + * See also [method@Gtk.AppChooserButton.append_separator]. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self, + const char *name, + const char *label, + GIcon *icon) +{ + GtkTreeIter iter; + + g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); + g_return_if_fail (name != NULL); + + gtk_list_store_append (self->store, &iter); + real_insert_custom_item (self, name, label, icon, TRUE, &iter); +} + +/** + * gtk_app_chooser_button_set_active_custom_item: + * @self: a `GtkAppChooserButton` + * @name: the name of the custom item + * + * Selects a custom item. + * + * See [method@Gtk.AppChooserButton.append_custom_item]. + * + * Use [method@Gtk.AppChooser.refresh] to bring the selection + * to its initial state. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self, + const char *name) +{ + GtkTreeIter iter; + + g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); + g_return_if_fail (name != NULL); + + if (!g_hash_table_contains (self->custom_item_names, name) || + !app_chooser_button_iter_from_custom_name (self, name, &iter)) + { + g_warning ("Can't find the item named %s in the app chooser.", name); + return; + } + + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), &iter); +} + +/** + * gtk_app_chooser_button_get_show_dialog_item: (attributes org.gtk.Method.get_property=show-dialog-item) + * @self: a `GtkAppChooserButton` + * + * Returns whether the dropdown menu shows an item + * for a `GtkAppChooserDialog`. + * + * Returns: the value of [property@Gtk.AppChooserButton:show-dialog-item] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_button_get_show_dialog_item (GtkAppChooserButton *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE); + + return self->show_dialog_item; +} + +/** + * gtk_app_chooser_button_set_show_dialog_item: (attributes org.gtk.Method.set_property=show-dialog-item) + * @self: a `GtkAppChooserButton` + * @setting: the new value for [property@Gtk.AppChooserButton:show-dialog-item] + * + * Sets whether the dropdown menu of this button should show an + * entry to trigger a `GtkAppChooserDialog`. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self, + gboolean setting) +{ + if (self->show_dialog_item != setting) + { + self->show_dialog_item = setting; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DIALOG_ITEM]); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_button_get_show_default_item: (attributes org.gtk.Method.get_property=show-default-item) + * @self: a `GtkAppChooserButton` + * + * Returns whether the dropdown menu should show the default + * application at the top. + * + * Returns: the value of [property@Gtk.AppChooserButton:show-default-item] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE); + + return self->show_default_item; +} + +/** + * gtk_app_chooser_button_set_show_default_item: (attributes org.gtk.Method.set_property=show-default-item) + * @self: a `GtkAppChooserButton` + * @setting: the new value for [property@Gtk.AppChooserButton:show-default-item] + * + * Sets whether the dropdown menu of this button should show the + * default application for the given content type at top. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self, + gboolean setting) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); + + if (self->show_default_item != setting) + { + self->show_default_item = setting; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DEFAULT_ITEM]); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_button_set_heading: (attributes org.gtk.Method.set_property=heading) + * @self: a `GtkAppChooserButton` + * @heading: a string containing Pango markup + * + * Sets the text to display at the top of the dialog. + * + * If the heading is not set, the dialog displays a default text. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_button_set_heading (GtkAppChooserButton *self, + const char *heading) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); + + g_free (self->heading); + self->heading = g_strdup (heading); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADING]); +} + +/** + * gtk_app_chooser_button_get_heading: (attributes org.gtk.Method.get_property=heading) + * @self: a `GtkAppChooserButton` + * + * Returns the text to display at the top of the dialog. + * + * Returns: (nullable): the text to display at the top of the dialog, + * or %NULL, in which case a default text is displayed + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +const char * +gtk_app_chooser_button_get_heading (GtkAppChooserButton *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), NULL); + + return self->heading; +} + +/** + * gtk_app_chooser_button_set_modal: (attributes org.gtk.Method.set_property=modal) + * @self: a `GtkAppChooserButton` + * @modal: %TRUE to make the dialog modal + * + * Sets whether the dialog should be modal. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_button_set_modal (GtkAppChooserButton *self, + gboolean modal) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); + + if (self->modal == modal) + return; + + self->modal = modal; + + g_object_notify (G_OBJECT (self), "modal"); +} + +/** + * gtk_app_chooser_button_get_modal: (attributes org.gtk.Method.get_property=modal) + * @self: a `GtkAppChooserButton` + * + * Gets whether the dialog is modal. + * + * Returns: %TRUE if the dialog is modal + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_button_get_modal (GtkAppChooserButton *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE); + + return self->modal; +} + diff --git a/gtk/deprecated/gtkappchooserbutton.h b/gtk/deprecated/gtkappchooserbutton.h new file mode 100644 index 0000000000..6f3a739507 --- /dev/null +++ b/gtk/deprecated/gtkappchooserbutton.h @@ -0,0 +1,84 @@ +/* + * gtkappchooserbutton.h: an app-chooser button + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Cosimo Cecchi + */ + +#ifndef __GTK_APP_CHOOSER_BUTTON_H__ +#define __GTK_APP_CHOOSER_BUTTON_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_APP_CHOOSER_BUTTON (gtk_app_chooser_button_get_type ()) +#define GTK_APP_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_BUTTON, GtkAppChooserButton)) +#define GTK_IS_APP_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_BUTTON)) + +typedef struct _GtkAppChooserButton GtkAppChooserButton; + +GDK_AVAILABLE_IN_ALL +GType gtk_app_chooser_button_get_type (void) G_GNUC_CONST; + +GDK_DEPRECATED_IN_4_10 +GtkWidget * gtk_app_chooser_button_new (const char *content_type); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_button_append_separator (GtkAppChooserButton *self); +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self, + const char *name, + const char *label, + GIcon *icon); +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self, + const char *name); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self, + gboolean setting); +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_button_get_show_dialog_item (GtkAppChooserButton *self); +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_button_set_heading (GtkAppChooserButton *self, + const char *heading); +GDK_DEPRECATED_IN_4_10 +const char * + gtk_app_chooser_button_get_heading (GtkAppChooserButton *self); +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self, + gboolean setting); +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self); + +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_button_get_modal (GtkAppChooserButton *self); +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_button_set_modal (GtkAppChooserButton *self, + gboolean modal); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserButton, g_object_unref) + +G_END_DECLS + +#endif /* __GTK_APP_CHOOSER_BUTTON_H__ */ diff --git a/gtk/deprecated/gtkappchooserdialog.c b/gtk/deprecated/gtkappchooserdialog.c new file mode 100644 index 0000000000..96c7ed644b --- /dev/null +++ b/gtk/deprecated/gtkappchooserdialog.c @@ -0,0 +1,799 @@ +/* + * gtkappchooserdialog.c: an app-chooser dialog + * + * Copyright (C) 2004 Novell, Inc. + * Copyright (C) 2007, 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Dave Camp + * Alexander Larsson + * Cosimo Cecchi + */ + +/** + * GtkAppChooserDialog: + * + * `GtkAppChooserDialog` shows a `GtkAppChooserWidget` inside a `GtkDialog`. + * + * ![An example GtkAppChooserDialog](appchooserdialog.png) + * + * Note that `GtkAppChooserDialog` does not have any interesting methods + * of its own. Instead, you should get the embedded `GtkAppChooserWidget` + * using [method@Gtk.AppChooserDialog.get_widget] and call its methods if + * the generic [iface@Gtk.AppChooser] interface is not sufficient for + * your needs. + * + * To set the heading that is shown above the `GtkAppChooserWidget`, + * use [method@Gtk.AppChooserDialog.set_heading]. + */ +#include "config.h" + +#include "gtkappchooserdialog.h" + +#include "gtkappchooser.h" +#include "gtkappchooserprivate.h" + +#include "gtkmessagedialog.h" +#include "gtksettings.h" +#include "gtklabel.h" +#include "gtkbox.h" +#include "gtkbutton.h" +#include "gtkentry.h" +#include "gtktogglebutton.h" +#include "gtkheaderbar.h" +#include "gtkdialogprivate.h" +#include "gtksearchbar.h" +#include "gtksizegroup.h" + +#include +#include +#include + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +typedef struct _GtkAppChooserDialogClass GtkAppChooserDialogClass; + +struct _GtkAppChooserDialog { + GtkDialog parent; + + char *content_type; + GFile *gfile; + char *heading; + + GtkWidget *label; + GtkWidget *inner_box; + + GtkWidget *open_label; + + GtkWidget *search_bar; + GtkWidget *search_entry; + GtkWidget *app_chooser_widget; + GtkWidget *show_more_button; + GtkWidget *software_button; + + GtkSizeGroup *buttons; + + gboolean show_more_clicked; + gboolean dismissed; +}; + +struct _GtkAppChooserDialogClass { + GtkDialogClass parent_class; +}; + +enum { + PROP_GFILE = 1, + PROP_CONTENT_TYPE, + PROP_HEADING +}; + +static void gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface); +G_DEFINE_TYPE_WITH_CODE (GtkAppChooserDialog, gtk_app_chooser_dialog, GTK_TYPE_DIALOG, + G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER, + gtk_app_chooser_dialog_iface_init)); + + +static void +add_or_find_application (GtkAppChooserDialog *self) +{ + GAppInfo *app; + + app = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self)); + + if (app) + { + /* we don't care about reporting errors here */ + if (self->content_type) + g_app_info_set_as_last_used_for_type (app, + self->content_type, + NULL); + g_object_unref (app); + } +} + +static void +gtk_app_chooser_dialog_response (GtkDialog *dialog, + int response_id, + gpointer user_data) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (dialog); + + switch (response_id) + { + case GTK_RESPONSE_OK: + add_or_find_application (self); + break; + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_DELETE_EVENT: + self->dismissed = TRUE; + break; + default: + break; + } +} + +static void +widget_application_selected_cb (GtkAppChooserWidget *widget, + GAppInfo *app_info, + gpointer user_data) +{ + gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, TRUE); +} + +static void +widget_application_activated_cb (GtkAppChooserWidget *widget, + GAppInfo *app_info, + gpointer user_data) +{ + gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK); +} + +static char * +get_extension (const char *basename) +{ + char *p; + + p = strrchr (basename, '.'); + + if (p && *(p + 1) != '\0') + return g_strdup (p + 1); + + return NULL; +} + +static void +set_dialog_properties (GtkAppChooserDialog *self) +{ + char *name; + char *extension; + char *description; + char *string; + gboolean unknown; + char *title; + char *subtitle; + gboolean use_header; + GtkWidget *header; + + name = NULL; + extension = NULL; + description = NULL; + unknown = TRUE; + + if (self->gfile != NULL) + { + name = g_file_get_basename (self->gfile); + extension = get_extension (name); + } + + if (self->content_type) + { + description = g_content_type_get_description (self->content_type); + unknown = g_content_type_is_unknown (self->content_type); + } + + title = g_strdup (_("Select Application")); + subtitle = NULL; + string = NULL; + + if (name != NULL) + { + /* Translators: %s is a filename */ + subtitle = g_strdup_printf (_("Opening “%s”."), name); + string = g_strdup_printf (_("No applications found for “%s”"), name); + } + else if (self->content_type) + { + /* Translators: %s is a file type description */ + subtitle = g_strdup_printf (_("Opening “%s” files."), + unknown ? self->content_type : description); + string = g_strdup_printf (_("No applications found for “%s” files"), + unknown ? self->content_type : description); + } + + g_object_get (self, "use-header-bar", &use_header, NULL); + if (use_header) + { + GtkWidget *box, *label; + + header = gtk_dialog_get_header_bar (GTK_DIALOG (self)); + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_valign (box, GTK_ALIGN_CENTER); + + label = gtk_label_new (title); + gtk_widget_set_halign (label, GTK_ALIGN_CENTER); + gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + gtk_label_set_width_chars (GTK_LABEL (label), 5); + gtk_widget_add_css_class (label, "title"); + gtk_widget_set_parent (label, box); + + if (subtitle) + { + label = gtk_label_new (subtitle); + gtk_widget_set_halign (label, GTK_ALIGN_CENTER); + gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE); + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + gtk_widget_add_css_class (label, "subtitle"); + gtk_widget_set_parent (label, box); + } + + gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header), box); + } + else + { + gtk_window_set_title (GTK_WINDOW (self), _("Select Application")); + } + + if (self->heading != NULL) + { + gtk_label_set_markup (GTK_LABEL (self->label), self->heading); + gtk_widget_show (self->label); + } + else + { + gtk_widget_hide (self->label); + } + + gtk_app_chooser_widget_set_default_text (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget), + string); + + g_free (title); + g_free (subtitle); + g_free (name); + g_free (extension); + g_free (description); + g_free (string); +} + +static void +show_more_button_clicked_cb (GtkButton *button, + gpointer user_data) +{ + GtkAppChooserDialog *self = user_data; + + g_object_set (self->app_chooser_widget, + "show-recommended", TRUE, + "show-fallback", TRUE, + "show-other", TRUE, + NULL); + + gtk_widget_hide (self->show_more_button); + self->show_more_clicked = TRUE; +} + +static void +widget_notify_for_button_cb (GObject *source, + GParamSpec *pspec, + gpointer user_data) +{ + GtkAppChooserDialog *self = user_data; + GtkAppChooserWidget *widget = GTK_APP_CHOOSER_WIDGET (source); + gboolean should_hide; + + should_hide = gtk_app_chooser_widget_get_show_other (widget) || + self->show_more_clicked; + + if (should_hide) + gtk_widget_hide (self->show_more_button); +} + +static void +construct_appchooser_widget (GtkAppChooserDialog *self) +{ + GAppInfo *info; + + /* Need to build the appchooser widget after, because of the content-type construct-only property */ + self->app_chooser_widget = gtk_app_chooser_widget_new (self->content_type); + gtk_widget_set_vexpand (self->app_chooser_widget, TRUE); + gtk_box_append (GTK_BOX (self->inner_box), self->app_chooser_widget); + + g_signal_connect (self->app_chooser_widget, "application-selected", + G_CALLBACK (widget_application_selected_cb), self); + g_signal_connect (self->app_chooser_widget, "application-activated", + G_CALLBACK (widget_application_activated_cb), self); + g_signal_connect (self->app_chooser_widget, "notify::show-other", + G_CALLBACK (widget_notify_for_button_cb), self); + + /* Add the custom button to the new appchooser */ + gtk_box_append (GTK_BOX (self->inner_box), + self->show_more_button); + + gtk_box_append (GTK_BOX (self->inner_box), + self->software_button); + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget)); + gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK, info != NULL); + if (info) + g_object_unref (info); + + _gtk_app_chooser_widget_set_search_entry (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget), + GTK_EDITABLE (self->search_entry)); + + gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (self->search_bar), + GTK_WIDGET (self)); +} + +static void +set_gfile_and_content_type (GtkAppChooserDialog *self, + GFile *file) +{ + GFileInfo *info; + + if (file == NULL) + return; + + self->gfile = g_object_ref (file); + + info = g_file_query_info (self->gfile, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + 0, NULL, NULL); + self->content_type = g_strdup (g_file_info_get_content_type (info)); + + g_object_unref (info); +} + +static GAppInfo * +gtk_app_chooser_dialog_get_app_info (GtkAppChooser *object) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); + + return gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget)); +} + +static void +gtk_app_chooser_dialog_refresh (GtkAppChooser *object) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self->app_chooser_widget)); +} + +static void +show_error_dialog (const char *primary, + const char *secondary, + GtkWindow *parent) +{ + GtkWidget *message_dialog; + + message_dialog = gtk_message_dialog_new (parent, 0, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + NULL); + g_object_set (message_dialog, + "text", primary, + "secondary-text", secondary, + NULL); + gtk_dialog_set_default_response (GTK_DIALOG (message_dialog), GTK_RESPONSE_OK); + + gtk_widget_show (message_dialog); + + g_signal_connect (message_dialog, "response", + G_CALLBACK (gtk_window_destroy), NULL); +} + +static void +software_button_clicked_cb (GtkButton *button, + GtkAppChooserDialog *self) +{ + GSubprocess *process; + GError *error = NULL; + char *option; + + if (self->content_type) + option = g_strconcat ("--search=", self->content_type, NULL); + else + option = g_strdup ("--mode=overview"); + + process = g_subprocess_new (0, &error, "gnome-software", option, NULL); + if (!process) + { + show_error_dialog (_("Failed to start GNOME Software"), + error->message, GTK_WINDOW (self)); + g_error_free (error); + } + else + g_object_unref (process); + + g_free (option); +} + +static void +ensure_software_button (GtkAppChooserDialog *self) +{ + char *path; + + path = g_find_program_in_path ("gnome-software"); + if (path != NULL) + gtk_widget_show (self->software_button); + else + gtk_widget_hide (self->software_button); + + g_free (path); +} + +static void +setup_search (GtkAppChooserDialog *self) +{ + gboolean use_header; + + g_object_get (self, "use-header-bar", &use_header, NULL); + if (use_header) + { + GtkWidget *button; + GtkWidget *image; + GtkWidget *header; + + button = gtk_toggle_button_new (); + gtk_widget_set_valign (button, GTK_ALIGN_CENTER); + image = gtk_image_new_from_icon_name ("edit-find-symbolic"); + gtk_button_set_child (GTK_BUTTON (button), image); + gtk_widget_add_css_class (button, "image-button"); + gtk_widget_remove_css_class (button, "text-button"); + + header = gtk_dialog_get_header_bar (GTK_DIALOG (self)); + gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button); + gtk_size_group_add_widget (self->buttons, button); + + g_object_bind_property (button, "active", + self->search_bar, "search-mode-enabled", + G_BINDING_BIDIRECTIONAL); + g_object_bind_property (self->search_entry, "sensitive", + button, "sensitive", + G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); + } +} + +static void +gtk_app_chooser_dialog_constructed (GObject *object) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); + + if (G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed != NULL) + G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed (object); + + construct_appchooser_widget (self); + set_dialog_properties (self); + ensure_software_button (self); + setup_search (self); +} + +static void +gtk_app_chooser_dialog_dispose (GObject *object) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); + + g_clear_object (&self->gfile); + + self->dismissed = TRUE; + + G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->dispose (object); +} + +static void +gtk_app_chooser_dialog_finalize (GObject *object) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); + + g_free (self->content_type); + g_free (self->heading); + + G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->finalize (object); +} + +static void +gtk_app_chooser_dialog_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); + + switch (property_id) + { + case PROP_GFILE: + set_gfile_and_content_type (self, g_value_get_object (value)); + break; + case PROP_CONTENT_TYPE: + /* don't try to override a value previously set with the GFile */ + if (self->content_type == NULL) + self->content_type = g_value_dup_string (value); + break; + case PROP_HEADING: + gtk_app_chooser_dialog_set_heading (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_app_chooser_dialog_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); + + switch (property_id) + { + case PROP_GFILE: + if (self->gfile != NULL) + g_value_set_object (value, self->gfile); + break; + case PROP_CONTENT_TYPE: + g_value_set_string (value, self->content_type); + break; + case PROP_HEADING: + g_value_set_string (value, self->heading); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface) +{ + iface->get_app_info = gtk_app_chooser_dialog_get_app_info; + iface->refresh = gtk_app_chooser_dialog_refresh; +} + +static void +gtk_app_chooser_dialog_class_init (GtkAppChooserDialogClass *klass) +{ + GObjectClass *gobject_class; + GtkWidgetClass *widget_class; + GParamSpec *pspec; + + gobject_class = G_OBJECT_CLASS (klass); + widget_class = GTK_WIDGET_CLASS (klass); + + gobject_class->dispose = gtk_app_chooser_dialog_dispose; + gobject_class->finalize = gtk_app_chooser_dialog_finalize; + gobject_class->set_property = gtk_app_chooser_dialog_set_property; + gobject_class->get_property = gtk_app_chooser_dialog_get_property; + gobject_class->constructed = gtk_app_chooser_dialog_constructed; + + g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type"); + + /** + * GtkAppChooserDialog:gfile: + * + * The GFile used by the `GtkAppChooserDialog`. + * + * The dialog's `GtkAppChooserWidget` content type will + * be guessed from the file, if present. + */ + pspec = g_param_spec_object ("gfile", NULL, NULL, + G_TYPE_FILE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_property (gobject_class, PROP_GFILE, pspec); + + /** + * GtkAppChooserDialog:heading: (attributes org.gtk.Property.get=gtk_app_chooser_dialog_get_heading org.gtk.Property.set=gtk_app_chooser_dialog_set_heading) + * + * The text to show at the top of the dialog. + * + * The string may contain Pango markup. + */ + pspec = g_param_spec_string ("heading", NULL, NULL, + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_property (gobject_class, PROP_HEADING, pspec); + + /* Bind class to template + */ + gtk_widget_class_set_template_from_resource (widget_class, + "/org/gtk/libgtk/ui/gtkappchooserdialog.ui"); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, label); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, show_more_button); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, software_button); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, inner_box); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_bar); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_entry); + gtk_widget_class_bind_template_child(widget_class, GtkAppChooserDialog, buttons); + gtk_widget_class_bind_template_callback (widget_class, show_more_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, software_button_clicked_cb); +} + +static void +gtk_app_chooser_dialog_init (GtkAppChooserDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (self)); + + /* we can't override the class signal handler here, as it's a RUN_LAST; + * we want our signal handler instead to be executed before any user code. + */ + g_signal_connect (self, "response", + G_CALLBACK (gtk_app_chooser_dialog_response), NULL); +} + +static void +set_parent_and_flags (GtkWidget *dialog, + GtkWindow *parent, + GtkDialogFlags flags) +{ + if (parent != NULL) + gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); + + if (flags & GTK_DIALOG_MODAL) + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + + if (flags & GTK_DIALOG_DESTROY_WITH_PARENT) + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); +} + +/** + * gtk_app_chooser_dialog_new: + * @parent: (nullable): a `GtkWindow` + * @flags: flags for this dialog + * @file: a `GFile` + * + * Creates a new `GtkAppChooserDialog` for the provided `GFile`. + * + * The dialog will show applications that can open the file. + * + * Returns: a newly created `GtkAppChooserDialog` + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +GtkWidget * +gtk_app_chooser_dialog_new (GtkWindow *parent, + GtkDialogFlags flags, + GFile *file) +{ + GtkWidget *retval; + + g_return_val_if_fail (G_IS_FILE (file), NULL); + + retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG, + "gfile", file, + NULL); + + set_parent_and_flags (retval, parent, flags); + + return retval; +} + +/** + * gtk_app_chooser_dialog_new_for_content_type: + * @parent: (nullable): a `GtkWindow` + * @flags: flags for this dialog + * @content_type: a content type string + * + * Creates a new `GtkAppChooserDialog` for the provided content type. + * + * The dialog will show applications that can open the content type. + * + * Returns: a newly created `GtkAppChooserDialog` + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +GtkWidget * +gtk_app_chooser_dialog_new_for_content_type (GtkWindow *parent, + GtkDialogFlags flags, + const char *content_type) +{ + GtkWidget *retval; + + g_return_val_if_fail (content_type != NULL, NULL); + + retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG, + "content-type", content_type, + NULL); + + set_parent_and_flags (retval, parent, flags); + + return retval; +} + +/** + * gtk_app_chooser_dialog_get_widget: + * @self: a `GtkAppChooserDialog` + * + * Returns the `GtkAppChooserWidget` of this dialog. + * + * Returns: (transfer none): the `GtkAppChooserWidget` of @self + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +GtkWidget * +gtk_app_chooser_dialog_get_widget (GtkAppChooserDialog *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL); + + return self->app_chooser_widget; +} + +/** + * gtk_app_chooser_dialog_set_heading: (attributes org.gtk.Method.set_property=heading) + * @self: a `GtkAppChooserDialog` + * @heading: a string containing Pango markup + * + * Sets the text to display at the top of the dialog. + * + * If the heading is not set, the dialog displays a default text. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_dialog_set_heading (GtkAppChooserDialog *self, + const char *heading) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self)); + + g_free (self->heading); + self->heading = g_strdup (heading); + + if (self->label) + { + if (self->heading) + { + gtk_label_set_markup (GTK_LABEL (self->label), self->heading); + gtk_widget_show (self->label); + } + else + { + gtk_widget_hide (self->label); + } + } + + g_object_notify (G_OBJECT (self), "heading"); +} + +/** + * gtk_app_chooser_dialog_get_heading: (attributes org.gtk.Method.get_property=heading) + * @self: a `GtkAppChooserDialog` + * + * Returns the text to display at the top of the dialog. + * + * Returns: (nullable): the text to display at the top of the dialog, + * or %NULL, in which case a default text is displayed + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +const char * +gtk_app_chooser_dialog_get_heading (GtkAppChooserDialog *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL); + + return self->heading; +} diff --git a/gtk/deprecated/gtkappchooserdialog.h b/gtk/deprecated/gtkappchooserdialog.h new file mode 100644 index 0000000000..80e926932a --- /dev/null +++ b/gtk/deprecated/gtkappchooserdialog.h @@ -0,0 +1,67 @@ +/* + * gtkappchooserdialog.h: an app-chooser dialog + * + * Copyright (C) 2004 Novell, Inc. + * Copyright (C) 2007, 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Dave Camp + * Alexander Larsson + * Cosimo Cecchi + */ + +#ifndef __GTK_APP_CHOOSER_DIALOG_H__ +#define __GTK_APP_CHOOSER_DIALOG_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_APP_CHOOSER_DIALOG (gtk_app_chooser_dialog_get_type ()) +#define GTK_APP_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_DIALOG, GtkAppChooserDialog)) +#define GTK_IS_APP_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_DIALOG)) + +typedef struct _GtkAppChooserDialog GtkAppChooserDialog; + +GDK_AVAILABLE_IN_ALL +GType gtk_app_chooser_dialog_get_type (void) G_GNUC_CONST; + +GDK_DEPRECATED_IN_4_10 +GtkWidget * gtk_app_chooser_dialog_new (GtkWindow *parent, + GtkDialogFlags flags, + GFile *file); +GDK_DEPRECATED_IN_4_10 +GtkWidget * gtk_app_chooser_dialog_new_for_content_type (GtkWindow *parent, + GtkDialogFlags flags, + const char *content_type); + +GDK_DEPRECATED_IN_4_10 +GtkWidget * gtk_app_chooser_dialog_get_widget (GtkAppChooserDialog *self); +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_dialog_set_heading (GtkAppChooserDialog *self, + const char *heading); +GDK_DEPRECATED_IN_4_10 +const char * gtk_app_chooser_dialog_get_heading (GtkAppChooserDialog *self); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserDialog, g_object_unref) + +G_END_DECLS + +#endif /* __GTK_APP_CHOOSER_DIALOG_H__ */ diff --git a/gtk/deprecated/gtkappchooserprivate.h b/gtk/deprecated/gtkappchooserprivate.h new file mode 100644 index 0000000000..754619adc7 --- /dev/null +++ b/gtk/deprecated/gtkappchooserprivate.h @@ -0,0 +1,53 @@ +/* + * gtkappchooserprivate.h: app-chooser interface + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Cosimo Cecchi + */ + +#ifndef __GTK_APP_CHOOSER_PRIVATE_H__ +#define __GTK_APP_CHOOSER_PRIVATE_H__ + +#include +#include + +#include "gtkappchooser.h" +#include "gtkappchooserwidget.h" +#include "gtkentry.h" + +G_BEGIN_DECLS + +typedef struct _GtkAppChooserIface GtkAppChooserIface; +typedef GtkAppChooserIface GtkAppChooserInterface; + +#define GTK_APP_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_APP_CHOOSER, GtkAppChooserIface)) + +struct _GtkAppChooserIface { + GTypeInterface base_iface; + + GAppInfo * (* get_app_info) (GtkAppChooser *object); + void (* refresh) (GtkAppChooser *object); +}; + +void +_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self, + GtkEditable *editable); + + +G_END_DECLS + +#endif /* __GTK_APP_CHOOSER_PRIVATE_H__ */ diff --git a/gtk/deprecated/gtkappchooserwidget.c b/gtk/deprecated/gtkappchooserwidget.c new file mode 100644 index 0000000000..fc662b2674 --- /dev/null +++ b/gtk/deprecated/gtkappchooserwidget.c @@ -0,0 +1,1408 @@ +/* + * gtkappchooserwidget.c: an app-chooser widget + * + * Copyright (C) 2004 Novell, Inc. + * Copyright (C) 2007, 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Dave Camp + * Alexander Larsson + * Cosimo Cecchi + */ + +#include "config.h" + +#include "gtkappchooserwidget.h" + +#include "gtkmarshalers.h" +#include "gtkappchooserwidget.h" +#include "gtkappchooserprivate.h" +#include "gtkliststore.h" +#include "gtktreeview.h" +#include "gtktreeselection.h" +#include "gtktreemodelsort.h" +#include "gtkorientable.h" +#include "gtkscrolledwindow.h" +#include "gtklabel.h" +#include "gtkgestureclick.h" +#include "gtkwidgetprivate.h" +#include "gtkprivate.h" + +#include +#include +#include + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +/** + * GtkAppChooserWidget: + * + * `GtkAppChooserWidget` is a widget for selecting applications. + * + * It is the main building block for [class@Gtk.AppChooserDialog]. + * Most applications only need to use the latter; but you can use + * this widget as part of a larger widget if you have special needs. + * + * `GtkAppChooserWidget` offers detailed control over what applications + * are shown, using the + * [property@Gtk.AppChooserWidget:show-default], + * [property@Gtk.AppChooserWidget:show-recommended], + * [property@Gtk.AppChooserWidget:show-fallback], + * [property@Gtk.AppChooserWidget:show-other] and + * [property@Gtk.AppChooserWidget:show-all] properties. See the + * [iface@Gtk.AppChooser] documentation for more information about these + * groups of applications. + * + * To keep track of the selected application, use the + * [signal@Gtk.AppChooserWidget::application-selected] and + * [signal@Gtk.AppChooserWidget::application-activated] signals. + * + * # CSS nodes + * + * `GtkAppChooserWidget` has a single CSS node with name appchooser. + */ + +typedef struct _GtkAppChooserWidgetClass GtkAppChooserWidgetClass; + +struct _GtkAppChooserWidget { + GtkWidget parent_instance; + + GAppInfo *selected_app_info; + + GtkWidget *overlay; + + char *content_type; + char *default_text; + + guint show_default : 1; + guint show_recommended : 1; + guint show_fallback : 1; + guint show_other : 1; + guint show_all : 1; + + GtkWidget *program_list; + GtkListStore *program_list_store; + GtkWidget *no_apps_label; + GtkWidget *no_apps; + + GtkTreeViewColumn *column; + GtkCellRenderer *padding_renderer; + GtkCellRenderer *secondary_padding; + + GAppInfoMonitor *monitor; + + GtkWidget *popup_menu; +}; + +struct _GtkAppChooserWidgetClass { + GtkWidgetClass parent_class; + + void (* application_selected) (GtkAppChooserWidget *self, + GAppInfo *app_info); + + void (* application_activated) (GtkAppChooserWidget *self, + GAppInfo *app_info); +}; + +enum { + COLUMN_APP_INFO, + COLUMN_GICON, + COLUMN_NAME, + COLUMN_DESC, + COLUMN_EXEC, + COLUMN_DEFAULT, + COLUMN_HEADING, + COLUMN_HEADING_TEXT, + COLUMN_RECOMMENDED, + COLUMN_FALLBACK, + NUM_COLUMNS +}; + + +enum { + PROP_CONTENT_TYPE = 1, + PROP_GFILE, + PROP_SHOW_DEFAULT, + PROP_SHOW_RECOMMENDED, + PROP_SHOW_FALLBACK, + PROP_SHOW_OTHER, + PROP_SHOW_ALL, + PROP_DEFAULT_TEXT, + N_PROPERTIES +}; + +enum { + SIGNAL_APPLICATION_SELECTED, + SIGNAL_APPLICATION_ACTIVATED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS] = { 0, }; + +static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface); + +G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_WIDGET, + G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER, + gtk_app_chooser_widget_iface_init)); + +static void +refresh_and_emit_app_selected (GtkAppChooserWidget *self, + GtkTreeSelection *selection) +{ + GtkTreeModel *model; + GtkTreeIter iter; + GAppInfo *info = NULL; + gboolean should_emit = FALSE; + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1); + + if (info == NULL) + return; + + if (self->selected_app_info) + { + if (!g_app_info_equal (self->selected_app_info, info)) + { + should_emit = TRUE; + g_set_object (&self->selected_app_info, info); + } + } + else + { + should_emit = TRUE; + g_set_object (&self->selected_app_info, info); + } + + g_object_unref (info); + + if (should_emit) + g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0, + self->selected_app_info); +} + +static gboolean +path_is_heading (GtkTreeView *view, + GtkTreePath *path) +{ + GtkTreeIter iter; + GtkTreeModel *model; + gboolean res; + + model = gtk_tree_view_get_model (view); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + COLUMN_HEADING, &res, + -1); + + return res; +} + +static void +program_list_selection_activated (GtkTreeView *view, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data) +{ + GtkAppChooserWidget *self = user_data; + GtkTreeSelection *selection; + + if (path_is_heading (view, path)) + return; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list)); + + refresh_and_emit_app_selected (self, selection); + + g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0, + self->selected_app_info); +} + +static gboolean +gtk_app_chooser_search_equal_func (GtkTreeModel *model, + int column, + const char *key, + GtkTreeIter *iter, + gpointer user_data) +{ + char *name; + char *exec_name; + gboolean ret; + + if (key != NULL) + { + ret = TRUE; + + gtk_tree_model_get (model, iter, + COLUMN_NAME, &name, + COLUMN_EXEC, &exec_name, + -1); + + if ((name != NULL && g_str_match_string (key, name, TRUE)) || + (exec_name != NULL && g_str_match_string (key, exec_name, FALSE))) + ret = FALSE; + + g_free (name); + g_free (exec_name); + + return ret; + } + else + { + return TRUE; + } +} + +static int +gtk_app_chooser_sort_func (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + gboolean a_recommended, b_recommended; + gboolean a_fallback, b_fallback; + gboolean a_heading, b_heading; + gboolean a_default, b_default; + char *a_name, *b_name, *a_casefold, *b_casefold; + int retval = 0; + + /* this returns: + * - <0 if a should show before b + * - =0 if a is the same as b + * - >0 if a should show after b + */ + + gtk_tree_model_get (model, a, + COLUMN_NAME, &a_name, + COLUMN_RECOMMENDED, &a_recommended, + COLUMN_FALLBACK, &a_fallback, + COLUMN_HEADING, &a_heading, + COLUMN_DEFAULT, &a_default, + -1); + + gtk_tree_model_get (model, b, + COLUMN_NAME, &b_name, + COLUMN_RECOMMENDED, &b_recommended, + COLUMN_FALLBACK, &b_fallback, + COLUMN_HEADING, &b_heading, + COLUMN_DEFAULT, &b_default, + -1); + + /* the default one always wins */ + if (a_default && !b_default) + { + retval = -1; + goto out; + } + + if (b_default && !a_default) + { + retval = 1; + goto out; + } + + /* the recommended one always wins */ + if (a_recommended && !b_recommended) + { + retval = -1; + goto out; + } + + if (b_recommended && !a_recommended) + { + retval = 1; + goto out; + } + + /* the recommended one always wins */ + if (a_fallback && !b_fallback) + { + retval = -1; + goto out; + } + + if (b_fallback && !a_fallback) + { + retval = 1; + goto out; + } + + /* they're both recommended/fallback or not, so if one is a heading, wins */ + if (a_heading) + { + retval = -1; + goto out; + } + + if (b_heading) + { + retval = 1; + goto out; + } + + /* don't order by name recommended applications, but use GLib's ordering */ + if (!a_recommended) + { + a_casefold = a_name != NULL ? + g_utf8_casefold (a_name, -1) : NULL; + b_casefold = b_name != NULL ? + g_utf8_casefold (b_name, -1) : NULL; + + retval = g_strcmp0 (a_casefold, b_casefold); + + g_free (a_casefold); + g_free (b_casefold); + } + + out: + g_free (a_name); + g_free (b_name); + + return retval; +} + +static void +padding_cell_renderer_func (GtkTreeViewColumn *column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer user_data) +{ + gboolean heading; + + gtk_tree_model_get (model, iter, + COLUMN_HEADING, &heading, + -1); + if (heading) + g_object_set (cell, + "visible", FALSE, + "xpad", 0, + "ypad", 0, + NULL); + else + g_object_set (cell, + "visible", TRUE, + "xpad", 3, + "ypad", 3, + NULL); +} + +static gboolean +gtk_app_chooser_selection_func (GtkTreeSelection *selection, + GtkTreeModel *model, + GtkTreePath *path, + gboolean path_currently_selected, + gpointer user_data) +{ + GtkTreeIter iter; + gboolean heading; + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, + COLUMN_HEADING, &heading, + -1); + + return !heading; +} + +static int +compare_apps_func (gconstpointer a, + gconstpointer b) +{ + return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b)); +} + +static gboolean +gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self, + const char *heading_title, + gboolean show_headings, + gboolean recommended, + gboolean fallback, + GList *applications, + GList *exclude_apps) +{ + gboolean heading_added, unref_icon; + GtkTreeIter iter; + GAppInfo *app; + char *app_string, *bold_string; + GIcon *icon; + GList *l; + gboolean retval; + + retval = FALSE; + heading_added = FALSE; + bold_string = g_strdup_printf ("%s", heading_title); + + for (l = applications; l != NULL; l = l->next) + { + app = l->data; + + if (self->content_type != NULL && + !g_app_info_supports_uris (app) && + !g_app_info_supports_files (app)) + continue; + + if (g_list_find_custom (exclude_apps, app, + (GCompareFunc) compare_apps_func)) + continue; + + if (!heading_added && show_headings) + { + gtk_list_store_append (self->program_list_store, &iter); + gtk_list_store_set (self->program_list_store, &iter, + COLUMN_HEADING_TEXT, bold_string, + COLUMN_HEADING, TRUE, + COLUMN_RECOMMENDED, recommended, + COLUMN_FALLBACK, fallback, + -1); + + heading_added = TRUE; + } + + app_string = g_markup_printf_escaped ("%s", + g_app_info_get_name (app) != NULL ? + g_app_info_get_name (app) : ""); + + icon = g_app_info_get_icon (app); + unref_icon = FALSE; + if (icon == NULL) + { + icon = g_themed_icon_new ("application-x-executable"); + unref_icon = TRUE; + } + + gtk_list_store_append (self->program_list_store, &iter); + gtk_list_store_set (self->program_list_store, &iter, + COLUMN_APP_INFO, app, + COLUMN_GICON, icon, + COLUMN_NAME, g_app_info_get_name (app), + COLUMN_DESC, app_string, + COLUMN_EXEC, g_app_info_get_executable (app), + COLUMN_HEADING, FALSE, + COLUMN_RECOMMENDED, recommended, + COLUMN_FALLBACK, fallback, + -1); + + retval = TRUE; + + g_free (app_string); + if (unref_icon) + g_object_unref (icon); + } + + g_free (bold_string); + + return retval; +} + + +static void +gtk_app_chooser_add_default (GtkAppChooserWidget *self, + GAppInfo *app) +{ + GtkTreeIter iter; + GIcon *icon; + char *string; + gboolean unref_icon; + + unref_icon = FALSE; + string = g_strdup_printf ("%s", _("Default Application")); + + gtk_list_store_append (self->program_list_store, &iter); + gtk_list_store_set (self->program_list_store, &iter, + COLUMN_HEADING_TEXT, string, + COLUMN_HEADING, TRUE, + COLUMN_DEFAULT, TRUE, + -1); + + g_free (string); + + string = g_markup_printf_escaped ("%s", + g_app_info_get_name (app) != NULL ? + g_app_info_get_name (app) : ""); + + icon = g_app_info_get_icon (app); + if (icon == NULL) + { + icon = g_themed_icon_new ("application-x-executable"); + unref_icon = TRUE; + } + + gtk_list_store_append (self->program_list_store, &iter); + gtk_list_store_set (self->program_list_store, &iter, + COLUMN_APP_INFO, app, + COLUMN_GICON, icon, + COLUMN_NAME, g_app_info_get_name (app), + COLUMN_DESC, string, + COLUMN_EXEC, g_app_info_get_executable (app), + COLUMN_HEADING, FALSE, + COLUMN_DEFAULT, TRUE, + -1); + + g_free (string); + + if (unref_icon) + g_object_unref (icon); +} + +static void +update_no_applications_label (GtkAppChooserWidget *self) +{ + char *text = NULL, *desc = NULL; + const char *string; + + if (self->default_text == NULL) + { + if (self->content_type) + desc = g_content_type_get_description (self->content_type); + + string = text = g_strdup_printf (_("No applications found for “%s”."), desc); + g_free (desc); + } + else + { + string = self->default_text; + } + + gtk_label_set_text (GTK_LABEL (self->no_apps_label), string); + + g_free (text); +} + +static void +gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self) +{ + GtkTreeIter iter; + GAppInfo *info = NULL; + GtkTreeModel *model; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list)); + if (!gtk_tree_model_get_iter_first (model, &iter)) + return; + + while (info == NULL) + { + gtk_tree_model_get (model, &iter, + COLUMN_APP_INFO, &info, + -1); + + if (info != NULL) + break; + + if (!gtk_tree_model_iter_next (model, &iter)) + break; + } + + if (info != NULL) + { + GtkTreeSelection *selection; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list)); + gtk_tree_selection_select_iter (selection, &iter); + + g_object_unref (info); + } +} + +static void +gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self) +{ + GList *all_applications = NULL; + GList *recommended_apps = NULL; + GList *fallback_apps = NULL; + GList *exclude_apps = NULL; + GAppInfo *default_app = NULL; + gboolean show_headings; + gboolean apps_added; + + show_headings = TRUE; + apps_added = FALSE; + + if (self->show_all) + show_headings = FALSE; + + if (self->show_default && self->content_type) + { + default_app = g_app_info_get_default_for_type (self->content_type, FALSE); + + if (default_app != NULL) + { + gtk_app_chooser_add_default (self, default_app); + apps_added = TRUE; + exclude_apps = g_list_prepend (exclude_apps, default_app); + } + } + +#ifndef G_OS_WIN32 + if ((self->content_type && self->show_recommended) || self->show_all) + { + if (self->content_type) + recommended_apps = g_app_info_get_recommended_for_type (self->content_type); + + apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"), + show_headings, + !self->show_all, /* mark as recommended */ + FALSE, /* mark as fallback */ + recommended_apps, exclude_apps); + + exclude_apps = g_list_concat (exclude_apps, + g_list_copy (recommended_apps)); + } + + if ((self->content_type && self->show_fallback) || self->show_all) + { + if (self->content_type) + fallback_apps = g_app_info_get_fallback_for_type (self->content_type); + + apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"), + show_headings, + FALSE, /* mark as recommended */ + !self->show_all, /* mark as fallback */ + fallback_apps, exclude_apps); + exclude_apps = g_list_concat (exclude_apps, + g_list_copy (fallback_apps)); + } +#endif + + if (self->show_other || self->show_all) + { + all_applications = g_app_info_get_all (); + + apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"), + show_headings, + FALSE, + FALSE, + all_applications, exclude_apps); + } + + if (!apps_added) + update_no_applications_label (self); + + gtk_widget_set_visible (self->no_apps, !apps_added); + + gtk_app_chooser_widget_select_first (self); + + if (default_app != NULL) + g_object_unref (default_app); + + g_list_free_full (all_applications, g_object_unref); + g_list_free_full (recommended_apps, g_object_unref); + g_list_free_full (fallback_apps, g_object_unref); + g_list_free (exclude_apps); +} + +static void +gtk_app_chooser_widget_initialize_items (GtkAppChooserWidget *self) +{ + /* initial padding */ + g_object_set (self->padding_renderer, + "xpad", self->show_all ? 0 : 6, + NULL); + + /* populate the widget */ + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); +} + +static void +app_info_changed (GAppInfoMonitor *monitor, + GtkAppChooserWidget *self) +{ + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); +} + +static void +gtk_app_chooser_widget_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); + + switch (property_id) + { + case PROP_CONTENT_TYPE: + self->content_type = g_value_dup_string (value); + break; + case PROP_SHOW_DEFAULT: + gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_RECOMMENDED: + gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_FALLBACK: + gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_OTHER: + gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value)); + break; + case PROP_SHOW_ALL: + gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value)); + break; + case PROP_DEFAULT_TEXT: + gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_app_chooser_widget_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); + + switch (property_id) + { + case PROP_CONTENT_TYPE: + g_value_set_string (value, self->content_type); + break; + case PROP_SHOW_DEFAULT: + g_value_set_boolean (value, self->show_default); + break; + case PROP_SHOW_RECOMMENDED: + g_value_set_boolean (value, self->show_recommended); + break; + case PROP_SHOW_FALLBACK: + g_value_set_boolean (value, self->show_fallback); + break; + case PROP_SHOW_OTHER: + g_value_set_boolean (value, self->show_other); + break; + case PROP_SHOW_ALL: + g_value_set_boolean (value, self->show_all); + break; + case PROP_DEFAULT_TEXT: + g_value_set_string (value, self->default_text); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_app_chooser_widget_constructed (GObject *object) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); + + if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL) + G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object); + + gtk_app_chooser_widget_initialize_items (self); +} + +static void +gtk_app_chooser_widget_finalize (GObject *object) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); + + g_free (self->content_type); + g_free (self->default_text); + g_signal_handlers_disconnect_by_func (self->monitor, app_info_changed, self); + g_object_unref (self->monitor); + + G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object); +} + +static void +gtk_app_chooser_widget_dispose (GObject *object) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); + + g_clear_object (&self->selected_app_info); + + if (self->overlay) + { + gtk_widget_unparent (self->overlay); + self->overlay = NULL; + } + + G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object); +} + +static void +gtk_app_chooser_widget_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum, + int *natural, + int *minimum_baseline, + int *natural_baseline) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget); + + gtk_widget_measure (self->overlay, orientation, for_size, + minimum, natural, + minimum_baseline, natural_baseline); +} + +static void +gtk_app_chooser_widget_snapshot (GtkWidget *widget, + GtkSnapshot *snapshot) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget); + + gtk_widget_snapshot_child (widget, self->overlay, snapshot); +} + +static void +gtk_app_chooser_widget_size_allocate (GtkWidget *widget, + int width, + int height, + int baseline) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget); + + GTK_WIDGET_CLASS (gtk_app_chooser_widget_parent_class)->size_allocate (widget, width, height, baseline); + + gtk_widget_size_allocate (self->overlay, + &(GtkAllocation) { + 0, 0, + width, height + },baseline); +} + +static void +gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) +{ + GtkWidgetClass *widget_class; + GObjectClass *gobject_class; + GParamSpec *pspec; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->dispose = gtk_app_chooser_widget_dispose; + gobject_class->finalize = gtk_app_chooser_widget_finalize; + gobject_class->set_property = gtk_app_chooser_widget_set_property; + gobject_class->get_property = gtk_app_chooser_widget_get_property; + gobject_class->constructed = gtk_app_chooser_widget_constructed; + + widget_class = GTK_WIDGET_CLASS (klass); + widget_class->measure = gtk_app_chooser_widget_measure; + widget_class->size_allocate = gtk_app_chooser_widget_size_allocate; + widget_class->snapshot = gtk_app_chooser_widget_snapshot; + + g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type"); + + /** + * GtkAppChooserWidget:show-default: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_default org.gtk.Property.set=gtk_app_chooser_widget_set_show_default) + * + * Determines whether the app chooser should show the default + * handler for the content type in a separate section. + * + * If %FALSE, the default handler is listed among the recommended + * applications. + */ + pspec = g_param_spec_boolean ("show-default", NULL, NULL, + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec); + + /** + * GtkAppChooserWidget:show-recommended: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_recommended org.gtk.Property.set=gtk_app_chooser_widget_set_show_recommended) + * + * Determines whether the app chooser should show a section + * for recommended applications. + * + * If %FALSE, the recommended applications are listed + * among the other applications. + */ + pspec = g_param_spec_boolean ("show-recommended", NULL, NULL, + TRUE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec); + + /** + * GtkAppChooserWidget:show-fallback: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_fallback org.gtk.Property.set=gtk_app_chooser_widget_set_show_fallback) + * + * Determines whether the app chooser should show a section + * for fallback applications. + * + * If %FALSE, the fallback applications are listed among the + * other applications. + */ + pspec = g_param_spec_boolean ("show-fallback", NULL, NULL, + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec); + + /** + * GtkAppChooserWidget:show-other: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_other org.gtk.Property.set=gtk_app_chooser_widget_set_show_other) + * + * Determines whether the app chooser should show a section + * for other applications. + */ + pspec = g_param_spec_boolean ("show-other", NULL, NULL, + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec); + + /** + * GtkAppChooserWidget:show-all: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_all org.gtk.Property.set=gtk_app_chooser_widget_set_show_all) + * + * If %TRUE, the app chooser presents all applications + * in a single list, without subsections for default, + * recommended or related applications. + */ + pspec = g_param_spec_boolean ("show-all", NULL, NULL, + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec); + + /** + * GtkAppChooserWidget:default-text: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_default_text org.gtk.Property.set=gtk_app_chooser_widget_set_default_text) + * + * The text that appears in the widget when there are no applications + * for the given content type. + */ + pspec = g_param_spec_string ("default-text", NULL, NULL, + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec); + + /** + * GtkAppChooserWidget::application-selected: + * @self: the object which received the signal + * @application: the selected `GAppInfo` + * + * Emitted when an application item is selected from the widget's list. + */ + signals[SIGNAL_APPLICATION_SELECTED] = + g_signal_new (I_("application-selected"), + GTK_TYPE_APP_CHOOSER_WIDGET, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected), + NULL, NULL, + NULL, + G_TYPE_NONE, + 1, G_TYPE_APP_INFO); + + /** + * GtkAppChooserWidget::application-activated: + * @self: the object which received the signal + * @application: the activated `GAppInfo` + * + * Emitted when an application item is activated from the widget's list. + * + * This usually happens when the user double clicks an item, or an item + * is selected and the user presses one of the keys Space, Shift+Space, + * Return or Enter. + */ + signals[SIGNAL_APPLICATION_ACTIVATED] = + g_signal_new (I_("application-activated"), + GTK_TYPE_APP_CHOOSER_WIDGET, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated), + NULL, NULL, + NULL, + G_TYPE_NONE, + 1, G_TYPE_APP_INFO); + + /* Bind class to template + */ + gtk_widget_class_set_template_from_resource (widget_class, + "/org/gtk/libgtk/ui/gtkappchooserwidget.ui"); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list_store); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, column); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, padding_renderer); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, secondary_padding); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps_label); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps); + gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, overlay); + gtk_widget_class_bind_template_callback (widget_class, refresh_and_emit_app_selected); + gtk_widget_class_bind_template_callback (widget_class, program_list_selection_activated); + + gtk_widget_class_set_css_name (widget_class, I_("appchooser")); +} + +static void +gtk_app_chooser_widget_init (GtkAppChooserWidget *self) +{ + GtkTreeSelection *selection; + GtkTreeModel *sort; + + gtk_widget_init_template (GTK_WIDGET (self)); + + /* Various parts of the GtkTreeView code need custom code to setup, mostly + * because we lack signals to connect to, or properties to set. + */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list)); + gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func, + self, NULL); + + sort = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list)); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), + COLUMN_NAME, + GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort), + COLUMN_NAME, + gtk_app_chooser_sort_func, + self, NULL); + + gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->program_list), COLUMN_NAME); + gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->program_list), + gtk_app_chooser_search_equal_func, + NULL, NULL); + + gtk_tree_view_column_set_cell_data_func (self->column, + self->secondary_padding, + padding_cell_renderer_func, + NULL, NULL); + + self->monitor = g_app_info_monitor_get (); + g_signal_connect (self->monitor, "changed", + G_CALLBACK (app_info_changed), self); +} + +static GAppInfo * +gtk_app_chooser_widget_get_app_info (GtkAppChooser *object) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); + + if (self->selected_app_info == NULL) + return NULL; + + return g_object_ref (self->selected_app_info); +} + +static void +gtk_app_chooser_widget_refresh (GtkAppChooser *object) +{ + GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); + + if (self->program_list_store != NULL) + { + gtk_list_store_clear (self->program_list_store); + + /* don't add additional xpad if we don't have headings */ + g_object_set (self->padding_renderer, + "visible", !self->show_all, + NULL); + + gtk_app_chooser_widget_real_add_items (self); + } +} + +static void +gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface) +{ + iface->get_app_info = gtk_app_chooser_widget_get_app_info; + iface->refresh = gtk_app_chooser_widget_refresh; +} + +/** + * gtk_app_chooser_widget_new: + * @content_type: the content type to show applications for + * + * Creates a new `GtkAppChooserWidget` for applications + * that can handle content of the given type. + * + * Returns: a newly created `GtkAppChooserWidget` + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +GtkWidget * +gtk_app_chooser_widget_new (const char *content_type) +{ + return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET, + "content-type", content_type, + NULL); +} + +/** + * gtk_app_chooser_widget_set_show_default: (attributes org.gtk.Method.set_property=show-default) + * @self: a `GtkAppChooserWidget` + * @setting: the new value for [property@Gtk.AppChooserWidget:show-default] + * + * Sets whether the app chooser should show the default handler + * for the content type in a separate section. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self, + gboolean setting) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); + + if (self->show_default != setting) + { + self->show_default = setting; + + g_object_notify (G_OBJECT (self), "show-default"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_widget_get_show_default: (attributes org.gtk.Method.get_property=show-default) + * @self: a `GtkAppChooserWidget` + * + * Gets whether the app chooser should show the default handler + * for the content type in a separate section. + * + * Returns: the value of [property@Gtk.AppChooserWidget:show-default] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); + + return self->show_default; +} + +/** + * gtk_app_chooser_widget_set_show_recommended: (attributes org.gtk.Method.set_property=show-recommended) + * @self: a `GtkAppChooserWidget` + * @setting: the new value for [property@Gtk.AppChooserWidget:show-recommended] + * + * Sets whether the app chooser should show recommended applications + * for the content type in a separate section. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self, + gboolean setting) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); + + if (self->show_recommended != setting) + { + self->show_recommended = setting; + + g_object_notify (G_OBJECT (self), "show-recommended"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_widget_get_show_recommended: (attributes org.gtk.Method.get_property=show-recommended) + * @self: a `GtkAppChooserWidget` + * + * Gets whether the app chooser should show recommended applications + * for the content type in a separate section. + * + * Returns: the value of [property@Gtk.AppChooserWidget:show-recommended] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); + + return self->show_recommended; +} + +/** + * gtk_app_chooser_widget_set_show_fallback: (attributes org.gtk.Method.set_property=show-fallback) + * @self: a `GtkAppChooserWidget` + * @setting: the new value for [property@Gtk.AppChooserWidget:show-fallback] + * + * Sets whether the app chooser should show related applications + * for the content type in a separate section. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self, + gboolean setting) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); + + if (self->show_fallback != setting) + { + self->show_fallback = setting; + + g_object_notify (G_OBJECT (self), "show-fallback"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_widget_get_show_fallback: (attributes org.gtk.Method.get_property=show-fallback) + * @self: a `GtkAppChooserWidget` + * + * Gets whether the app chooser should show related applications + * for the content type in a separate section. + * + * Returns: the value of [property@Gtk.AppChooserWidget:show-fallback] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); + + return self->show_fallback; +} + +/** + * gtk_app_chooser_widget_set_show_other: (attributes org.gtk.Method.set_property=show-other) + * @self: a `GtkAppChooserWidget` + * @setting: the new value for [property@Gtk.AppChooserWidget:show-other] + * + * Sets whether the app chooser should show applications + * which are unrelated to the content type. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self, + gboolean setting) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); + + if (self->show_other != setting) + { + self->show_other = setting; + + g_object_notify (G_OBJECT (self), "show-other"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_widget_get_show_other: (attributes org.gtk.Method.get_property=show-other) + * @self: a `GtkAppChooserWidget` + * + * Gets whether the app chooser should show applications + * which are unrelated to the content type. + * + * Returns: the value of [property@Gtk.AppChooserWidget:show-other] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); + + return self->show_other; +} + +/** + * gtk_app_chooser_widget_set_show_all: (attributes org.gtk.Method.set_property=show-all) + * @self: a `GtkAppChooserWidget` + * @setting: the new value for [property@Gtk.AppChooserWidget:show-all] + * + * Sets whether the app chooser should show all applications + * in a flat list. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self, + gboolean setting) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); + + if (self->show_all != setting) + { + self->show_all = setting; + + g_object_notify (G_OBJECT (self), "show-all"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_widget_get_show_all: (attributes org.gtk.Method.get_property=show-all) + * @self: a `GtkAppChooserWidget` + * + * Gets whether the app chooser should show all applications + * in a flat list. + * + * Returns: the value of [property@Gtk.AppChooserWidget:show-all] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +gboolean +gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); + + return self->show_all; +} + +/** + * gtk_app_chooser_widget_set_default_text: (attributes org.gtk.Method.set_property=default-text) + * @self: a `GtkAppChooserWidget` + * @text: the new value for [property@Gtk.AppChooserWidget:default-text] + * + * Sets the text that is shown if there are not applications + * that can handle the content type. + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +void +gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self, + const char *text) +{ + g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); + + if (g_strcmp0 (text, self->default_text) != 0) + { + g_free (self->default_text); + self->default_text = g_strdup (text); + + g_object_notify (G_OBJECT (self), "default-text"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } +} + +/** + * gtk_app_chooser_widget_get_default_text: (attributes org.gtk.Method.get_property=default-text) + * @self: a `GtkAppChooserWidget` + * + * Returns the text that is shown if there are not applications + * that can handle the content type. + * + * Returns: (nullable): the value of [property@Gtk.AppChooserWidget:default-text] + * + * Deprecated: 4.10: This widget will be removed in GTK 5 + */ +const char * +gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL); + + return self->default_text; +} + +void +_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self, + GtkEditable *entry) +{ + gtk_tree_view_set_search_entry (GTK_TREE_VIEW (self->program_list), entry); + + g_object_bind_property (self->no_apps, "visible", + entry, "sensitive", + G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); +} diff --git a/gtk/deprecated/gtkappchooserwidget.h b/gtk/deprecated/gtkappchooserwidget.h new file mode 100644 index 0000000000..75751dc9eb --- /dev/null +++ b/gtk/deprecated/gtkappchooserwidget.h @@ -0,0 +1,89 @@ +/* + * gtkappchooserwidget.h: an app-chooser widget + * + * Copyright (C) 2004 Novell, Inc. + * Copyright (C) 2007, 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + * + * Authors: Dave Camp + * Alexander Larsson + * Cosimo Cecchi + */ + +#ifndef __GTK_APP_CHOOSER_WIDGET_H__ +#define __GTK_APP_CHOOSER_WIDGET_H__ + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_APP_CHOOSER_WIDGET (gtk_app_chooser_widget_get_type ()) +#define GTK_APP_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_WIDGET, GtkAppChooserWidget)) +#define GTK_IS_APP_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_WIDGET)) + +typedef struct _GtkAppChooserWidget GtkAppChooserWidget; + +GDK_AVAILABLE_IN_ALL +GType gtk_app_chooser_widget_get_type (void) G_GNUC_CONST; + +GDK_DEPRECATED_IN_4_10 +GtkWidget * gtk_app_chooser_widget_new (const char *content_type); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self, + gboolean setting); +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self, + gboolean setting); +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self, + gboolean setting); +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self, + gboolean setting); +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self, + gboolean setting); +GDK_DEPRECATED_IN_4_10 +gboolean gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self); + +GDK_DEPRECATED_IN_4_10 +void gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self, + const char *text); +GDK_DEPRECATED_IN_4_10 +const char * gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserWidget, g_object_unref) + +G_END_DECLS + +#endif /* __GTK_APP_CHOOSER_WIDGET_H__ */ diff --git a/gtk/deprecated/meson.build b/gtk/deprecated/meson.build index 7e7916bcff..98c454ef73 100644 --- a/gtk/deprecated/meson.build +++ b/gtk/deprecated/meson.build @@ -1,5 +1,13 @@ -gtk_deprecated_sources = files([]) +gtk_deprecated_sources = [ + 'deprecated/gtkappchooser.c', + 'deprecated/gtkappchooserbutton.c', + 'deprecated/gtkappchooserdialog.c', + 'deprecated/gtkappchooserwidget.c', +] -gtk_deprecated_headers = files([]) - -install_headers(gtk_deprecated_headers, subdir: 'gtk-4.0/gtk/deprecated/') +gtk_deprecated_headers = [ + 'deprecated/gtkappchooser.h', + 'deprecated/gtkappchooserbutton.h', + 'deprecated/gtkappchooserdialog.h', + 'deprecated/gtkappchooserwidget.h', +] diff --git a/gtk/gtk.h b/gtk/gtk.h index f995ba4689..ff0a3eff62 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -37,10 +37,10 @@ #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include #include diff --git a/gtk/gtkappchooser.c b/gtk/gtkappchooser.c deleted file mode 100644 index 51b50f9749..0000000000 --- a/gtk/gtkappchooser.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * gtkappchooser.c: app-chooser interface - * - * Copyright (C) 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Cosimo Cecchi - */ - -/** - * GtkAppChooser: - * - * `GtkAppChooser` is an interface for widgets which allow the user to - * choose an application. - * - * The main objects that implement this interface are - * [class@Gtk.AppChooserWidget], - * [class@Gtk.AppChooserDialog] and [class@Gtk.AppChooserButton]. - * - * Applications are represented by GIO `GAppInfo` objects here. - * GIO has a concept of recommended and fallback applications for a - * given content type. Recommended applications are those that claim - * to handle the content type itself, while fallback also includes - * applications that handle a more generic content type. GIO also - * knows the default and last-used application for a given content - * type. The `GtkAppChooserWidget` provides detailed control over - * whether the shown list of applications should include default, - * recommended or fallback applications. - * - * To obtain the application that has been selected in a `GtkAppChooser`, - * use [method@Gtk.AppChooser.get_app_info]. - */ - -#include "config.h" - -#include "gtkappchooser.h" - -#include "gtkappchooserprivate.h" -#include "gtkwidget.h" - -#include - -G_DEFINE_INTERFACE (GtkAppChooser, gtk_app_chooser, GTK_TYPE_WIDGET); - -static void -gtk_app_chooser_default_init (GtkAppChooserIface *iface) -{ - GParamSpec *pspec; - - /** - * GtkAppChooser:content-type: (attributes org.gtk.Property.get=gtk_app_chooser_get_content_type) - * - * The content type of the `GtkAppChooser` object. - * - * See `GContentType` for more information about content types. - */ - pspec = g_param_spec_string ("content-type", NULL, NULL, - NULL, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS); - g_object_interface_install_property (iface, pspec); -} - - -/** - * gtk_app_chooser_get_content_type: (attributes org.gtk.Method.get_property=content-type) - * @self: a `GtkAppChooser` - * - * Returns the content type for which the `GtkAppChooser` - * shows applications. - * - * Returns: the content type of @self. Free with g_free() - */ -char * -gtk_app_chooser_get_content_type (GtkAppChooser *self) -{ - char *retval = NULL; - - g_return_val_if_fail (GTK_IS_APP_CHOOSER (self), NULL); - - g_object_get (self, - "content-type", &retval, - NULL); - - return retval; -} - -/** - * gtk_app_chooser_get_app_info: - * @self: a `GtkAppChooser` - * - * Returns the currently selected application. - * - * Returns: (nullable) (transfer full): a `GAppInfo` for the - * currently selected application - */ -GAppInfo * -gtk_app_chooser_get_app_info (GtkAppChooser *self) -{ - return GTK_APP_CHOOSER_GET_IFACE (self)->get_app_info (self); -} - -/** - * gtk_app_chooser_refresh: - * @self: a `GtkAppChooser` - * - * Reloads the list of applications. - */ -void -gtk_app_chooser_refresh (GtkAppChooser *self) -{ - GTK_APP_CHOOSER_GET_IFACE (self)->refresh (self); -} diff --git a/gtk/gtkappchooser.h b/gtk/gtkappchooser.h deleted file mode 100644 index 6777297b2a..0000000000 --- a/gtk/gtkappchooser.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * gtkappchooser.h: app-chooser interface - * - * Copyright (C) 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Cosimo Cecchi - */ - -#ifndef __GTK_APP_CHOOSER_H__ -#define __GTK_APP_CHOOSER_H__ - -#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) -#error "Only can be included directly." -#endif - -#include -#include -#include - -G_BEGIN_DECLS - -#define GTK_TYPE_APP_CHOOSER (gtk_app_chooser_get_type ()) -#define GTK_APP_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER, GtkAppChooser)) -#define GTK_IS_APP_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER)) - -typedef struct _GtkAppChooser GtkAppChooser; - -GDK_AVAILABLE_IN_ALL -GType gtk_app_chooser_get_type (void) G_GNUC_CONST; - -GDK_AVAILABLE_IN_ALL -GAppInfo * gtk_app_chooser_get_app_info (GtkAppChooser *self); -GDK_AVAILABLE_IN_ALL -char * gtk_app_chooser_get_content_type (GtkAppChooser *self); -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_refresh (GtkAppChooser *self); - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooser, g_object_unref) - -G_END_DECLS - -#endif /* __GTK_APP_CHOOSER_H__ */ - diff --git a/gtk/gtkappchooserbutton.c b/gtk/gtkappchooserbutton.c deleted file mode 100644 index fb820513e1..0000000000 --- a/gtk/gtkappchooserbutton.c +++ /dev/null @@ -1,1132 +0,0 @@ -/* gtkappchooserbutton.c: an app-chooser button - * - * Copyright (C) 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Cosimo Cecchi - */ - -/** - * GtkAppChooserButton: - * - * The `GtkAppChooserButton` lets the user select an application. - * - * ![An example GtkAppChooserButton](appchooserbutton.png) - * - * Initially, a `GtkAppChooserButton` selects the first application - * in its list, which will either be the most-recently used application - * or, if [property@Gtk.AppChooserButton:show-default-item] is %TRUE, the - * default application. - * - * The list of applications shown in a `GtkAppChooserButton` includes - * the recommended applications for the given content type. When - * [property@Gtk.AppChooserButton:show-default-item] is set, the default - * application is also included. To let the user chooser other applications, - * you can set the [property@Gtk.AppChooserButton:show-dialog-item] property, - * which allows to open a full [class@Gtk.AppChooserDialog]. - * - * It is possible to add custom items to the list, using - * [method@Gtk.AppChooserButton.append_custom_item]. These items cause - * the [signal@Gtk.AppChooserButton::custom-item-activated] signal to be - * emitted when they are selected. - * - * To track changes in the selected application, use the - * [signal@Gtk.AppChooserButton::changed] signal. - * - * # CSS nodes - * - * `GtkAppChooserButton` has a single CSS node with the name “appchooserbutton”. - */ -#include "config.h" - -#include "gtkappchooserbutton.h" - -#include "gtkappchooser.h" -#include "gtkappchooserdialog.h" -#include "gtkappchooserprivate.h" -#include "gtkcelllayout.h" -#include "gtkcellrendererpixbuf.h" -#include "gtkcellrenderertext.h" -#include "gtkcombobox.h" -#include "gtkwidgetprivate.h" -#include "gtkdialog.h" -#include -#include "gtkmarshalers.h" -#include "gtkliststore.h" -#include "gtkprivate.h" - -enum { - PROP_SHOW_DIALOG_ITEM = 1, - PROP_SHOW_DEFAULT_ITEM, - PROP_HEADING, - PROP_MODAL, - NUM_PROPERTIES, - - PROP_CONTENT_TYPE = NUM_PROPERTIES -}; - -enum { - SIGNAL_CHANGED, - SIGNAL_CUSTOM_ITEM_ACTIVATED, - ACTIVATE, - NUM_SIGNALS -}; - -enum { - COLUMN_APP_INFO, - COLUMN_NAME, - COLUMN_LABEL, - COLUMN_ICON, - COLUMN_CUSTOM, - COLUMN_SEPARATOR, - NUM_COLUMNS, -}; - -#define CUSTOM_ITEM_OTHER_APP "gtk-internal-item-other-app" - -static void app_chooser_iface_init (GtkAppChooserIface *iface); - -static void real_insert_custom_item (GtkAppChooserButton *self, - const char *name, - const char *label, - GIcon *icon, - gboolean custom, - GtkTreeIter *iter); - -static void real_insert_separator (GtkAppChooserButton *self, - gboolean custom, - GtkTreeIter *iter); - -static guint signals[NUM_SIGNALS] = { 0, }; -static GParamSpec *properties[NUM_PROPERTIES]; - -typedef struct _GtkAppChooserButtonClass GtkAppChooserButtonClass; - -struct _GtkAppChooserButton { - GtkWidget parent_instance; - - GtkWidget *combobox; - GtkListStore *store; - - char *content_type; - char *heading; - int last_active; - gboolean show_dialog_item; - gboolean show_default_item; - gboolean modal; - - GHashTable *custom_item_names; -}; - -struct _GtkAppChooserButtonClass { - GtkWidgetClass parent_class; - - void (* changed) (GtkAppChooserButton *self); - void (* custom_item_activated) (GtkAppChooserButton *self, - const char *item_name); - void (* activate) (GtkAppChooserButton *self); -}; - -G_DEFINE_TYPE_WITH_CODE (GtkAppChooserButton, gtk_app_chooser_button, GTK_TYPE_WIDGET, - G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER, - app_chooser_iface_init)); - -static gboolean -row_separator_func (GtkTreeModel *model, - GtkTreeIter *iter, - gpointer user_data) -{ - gboolean separator; - - gtk_tree_model_get (model, iter, - COLUMN_SEPARATOR, &separator, - -1); - - return separator; -} - -static void -get_first_iter (GtkListStore *store, - GtkTreeIter *iter) -{ - GtkTreeIter iter2; - - if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), iter)) - { - /* the model is empty, append */ - gtk_list_store_append (store, iter); - } - else - { - gtk_list_store_insert_before (store, &iter2, iter); - *iter = iter2; - } -} - -typedef struct { - GtkAppChooserButton *self; - GAppInfo *info; - int active_index; -} SelectAppData; - -static void -select_app_data_free (SelectAppData *data) -{ - g_clear_object (&data->self); - g_clear_object (&data->info); - - g_slice_free (SelectAppData, data); -} - -static gboolean -select_application_func_cb (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - gpointer user_data) -{ - SelectAppData *data = user_data; - GtkAppChooserButton *self = data->self; - GAppInfo *app_to_match = data->info; - GAppInfo *app = NULL; - gboolean custom; - gboolean result; - - gtk_tree_model_get (model, iter, - COLUMN_APP_INFO, &app, - COLUMN_CUSTOM, &custom, - -1); - - /* custom items are always after GAppInfos, so iterating further here - * is just useless. - */ - if (custom) - result = TRUE; - else if (g_app_info_equal (app, app_to_match)) - { - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), iter); - result = TRUE; - } - else - result = FALSE; - - g_object_unref (app); - - return result; -} - -static void -gtk_app_chooser_button_select_application (GtkAppChooserButton *self, - GAppInfo *info) -{ - SelectAppData *data; - - data = g_slice_new0 (SelectAppData); - data->self = g_object_ref (self); - data->info = g_object_ref (info); - - gtk_tree_model_foreach (GTK_TREE_MODEL (self->store), - select_application_func_cb, data); - - select_app_data_free (data); -} - -static void -other_application_dialog_response_cb (GtkDialog *dialog, - int response_id, - gpointer user_data) -{ - GtkAppChooserButton *self = user_data; - GAppInfo *info; - - if (response_id != GTK_RESPONSE_OK) - { - /* reset the active item, otherwise we are stuck on - * 'Other application…' - */ - gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), self->last_active); - gtk_window_destroy (GTK_WINDOW (dialog)); - return; - } - - info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog)); - - gtk_window_destroy (GTK_WINDOW (dialog)); - - /* refresh the combobox to get the new application */ - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - gtk_app_chooser_button_select_application (self, info); - - g_object_unref (info); -} - -static void -other_application_item_activated_cb (GtkAppChooserButton *self) -{ - GtkWidget *dialog, *widget; - GtkRoot *root; - - root = gtk_widget_get_root (GTK_WIDGET (self)); - dialog = gtk_app_chooser_dialog_new_for_content_type (GTK_WINDOW (root), - GTK_DIALOG_DESTROY_WITH_PARENT, - self->content_type); - gtk_window_set_modal (GTK_WINDOW (dialog), self->modal | gtk_window_get_modal (GTK_WINDOW (root))); - gtk_app_chooser_dialog_set_heading (GTK_APP_CHOOSER_DIALOG (dialog), self->heading); - - widget = gtk_app_chooser_dialog_get_widget (GTK_APP_CHOOSER_DIALOG (dialog)); - g_object_set (widget, - "show-fallback", TRUE, - "show-other", TRUE, - NULL); - gtk_widget_show (dialog); - - g_signal_connect (dialog, "response", - G_CALLBACK (other_application_dialog_response_cb), self); -} - -static void -gtk_app_chooser_button_ensure_dialog_item (GtkAppChooserButton *self, - GtkTreeIter *prev_iter) -{ - GtkTreeIter iter, iter2; - - if (!self->show_dialog_item || !self->content_type) - return; - - if (prev_iter == NULL) - gtk_list_store_append (self->store, &iter); - else - gtk_list_store_insert_after (self->store, &iter, prev_iter); - - real_insert_separator (self, FALSE, &iter); - iter2 = iter; - - gtk_list_store_insert_after (self->store, &iter, &iter2); - real_insert_custom_item (self, CUSTOM_ITEM_OTHER_APP, - _("Other application…"), NULL, - FALSE, &iter); -} - -static void -insert_one_application (GtkAppChooserButton *self, - GAppInfo *app, - GtkTreeIter *iter) -{ - GIcon *icon; - - icon = g_app_info_get_icon (app); - - if (icon == NULL) - icon = g_themed_icon_new ("application-x-executable"); - else - g_object_ref (icon); - - gtk_list_store_set (self->store, iter, - COLUMN_APP_INFO, app, - COLUMN_LABEL, g_app_info_get_name (app), - COLUMN_ICON, icon, - COLUMN_CUSTOM, FALSE, - -1); - - g_object_unref (icon); -} - -static void -gtk_app_chooser_button_populate (GtkAppChooserButton *self) -{ - GList *recommended_apps = NULL, *l; - GAppInfo *app, *default_app = NULL; - GtkTreeIter iter, iter2; - gboolean cycled_recommended; - -#ifndef G_OS_WIN32 - if (self->content_type) - recommended_apps = g_app_info_get_recommended_for_type (self->content_type); -#endif - cycled_recommended = FALSE; - - if (self->show_default_item) - { - if (self->content_type) - default_app = g_app_info_get_default_for_type (self->content_type, FALSE); - - if (default_app != NULL) - { - get_first_iter (self->store, &iter); - cycled_recommended = TRUE; - - insert_one_application (self, default_app, &iter); - - g_object_unref (default_app); - } - } - - for (l = recommended_apps; l != NULL; l = l->next) - { - app = l->data; - - if (default_app != NULL && g_app_info_equal (app, default_app)) - continue; - - if (cycled_recommended) - { - gtk_list_store_insert_after (self->store, &iter2, &iter); - iter = iter2; - } - else - { - get_first_iter (self->store, &iter); - cycled_recommended = TRUE; - } - - insert_one_application (self, app, &iter); - } - - if (recommended_apps != NULL) - g_list_free_full (recommended_apps, g_object_unref); - - if (!cycled_recommended) - gtk_app_chooser_button_ensure_dialog_item (self, NULL); - else - gtk_app_chooser_button_ensure_dialog_item (self, &iter); - - gtk_combo_box_set_active (GTK_COMBO_BOX (self->combobox), 0); -} - -static void -gtk_app_chooser_button_build_ui (GtkAppChooserButton *self) -{ - GtkCellRenderer *cell; - GtkCellArea *area; - - gtk_combo_box_set_model (GTK_COMBO_BOX (self->combobox), - GTK_TREE_MODEL (self->store)); - - area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (self->combobox)); - - gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (self->combobox), - row_separator_func, NULL, NULL); - - cell = gtk_cell_renderer_pixbuf_new (); - gtk_cell_area_add_with_properties (area, cell, - "align", FALSE, - "expand", FALSE, - "fixed-size", FALSE, - NULL); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell, - "gicon", COLUMN_ICON, - NULL); - - cell = gtk_cell_renderer_text_new (); - gtk_cell_area_add_with_properties (area, cell, - "align", FALSE, - "expand", TRUE, - NULL); - gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self->combobox), cell, - "text", COLUMN_LABEL, - NULL); - - gtk_app_chooser_button_populate (self); -} - -static void -gtk_app_chooser_button_remove_non_custom (GtkAppChooserButton *self) -{ - GtkTreeModel *model; - GtkTreeIter iter; - gboolean custom, res; - - model = GTK_TREE_MODEL (self->store); - - if (!gtk_tree_model_get_iter_first (model, &iter)) - return; - - do { - gtk_tree_model_get (model, &iter, - COLUMN_CUSTOM, &custom, - -1); - if (custom) - res = gtk_tree_model_iter_next (model, &iter); - else - res = gtk_list_store_remove (GTK_LIST_STORE (model), &iter); - } while (res); -} - -static void -gtk_app_chooser_button_changed (GtkComboBox *object, - gpointer user_data) -{ - GtkAppChooserButton *self = user_data; - GtkTreeIter iter; - char *name = NULL; - gboolean custom; - GQuark name_quark; - - if (!gtk_combo_box_get_active_iter (object, &iter)) - return; - - gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter, - COLUMN_NAME, &name, - COLUMN_CUSTOM, &custom, - -1); - - if (name != NULL) - { - if (custom) - { - name_quark = g_quark_from_string (name); - g_signal_emit (self, signals[SIGNAL_CUSTOM_ITEM_ACTIVATED], name_quark, name); - self->last_active = gtk_combo_box_get_active (object); - } - else - { - /* trigger the dialog internally */ - other_application_item_activated_cb (self); - } - - g_free (name); - } - else - self->last_active = gtk_combo_box_get_active (object); - - g_signal_emit (self, signals[SIGNAL_CHANGED], 0); -} - -static void -gtk_app_chooser_button_refresh (GtkAppChooser *object) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object); - - gtk_app_chooser_button_remove_non_custom (self); - gtk_app_chooser_button_populate (self); -} - -static GAppInfo * -gtk_app_chooser_button_get_app_info (GtkAppChooser *object) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (object); - GtkTreeIter iter; - GAppInfo *info; - - if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->combobox), &iter)) - return NULL; - - gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter, - COLUMN_APP_INFO, &info, - -1); - - return info; -} - -static void -gtk_app_chooser_button_constructed (GObject *obj) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); - - if (G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed != NULL) - G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->constructed (obj); - - gtk_app_chooser_button_build_ui (self); -} - -static void -gtk_app_chooser_button_set_property (GObject *obj, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); - - switch (property_id) - { - case PROP_CONTENT_TYPE: - self->content_type = g_value_dup_string (value); - break; - case PROP_SHOW_DIALOG_ITEM: - gtk_app_chooser_button_set_show_dialog_item (self, g_value_get_boolean (value)); - break; - case PROP_SHOW_DEFAULT_ITEM: - gtk_app_chooser_button_set_show_default_item (self, g_value_get_boolean (value)); - break; - case PROP_HEADING: - gtk_app_chooser_button_set_heading (self, g_value_get_string (value)); - break; - case PROP_MODAL: - gtk_app_chooser_button_set_modal (self, g_value_get_boolean (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); - break; - } -} - -static void -gtk_app_chooser_button_get_property (GObject *obj, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); - - switch (property_id) - { - case PROP_CONTENT_TYPE: - g_value_set_string (value, self->content_type); - break; - case PROP_SHOW_DIALOG_ITEM: - g_value_set_boolean (value, self->show_dialog_item); - break; - case PROP_SHOW_DEFAULT_ITEM: - g_value_set_boolean (value, self->show_default_item); - break; - case PROP_HEADING: - g_value_set_string (value, self->heading); - break; - case PROP_MODAL: - g_value_set_boolean (value, self->modal); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); - break; - } -} - -static void -gtk_app_chooser_button_finalize (GObject *obj) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (obj); - - g_hash_table_destroy (self->custom_item_names); - g_free (self->content_type); - g_free (self->heading); - g_object_unref (self->store); - gtk_widget_unparent (self->combobox); - - G_OBJECT_CLASS (gtk_app_chooser_button_parent_class)->finalize (obj); -} - -static void -gtk_app_chooser_button_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget); - - gtk_widget_measure (self->combobox, orientation, for_size, - minimum, natural, - minimum_baseline, natural_baseline); -} - -static void -gtk_app_chooser_button_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline) -{ - GtkAppChooserButton *self = GTK_APP_CHOOSER_BUTTON (widget); - - gtk_widget_size_allocate (self->combobox, &(GtkAllocation){0, 0, width, height}, baseline); -} - -static void -app_chooser_iface_init (GtkAppChooserIface *iface) -{ - iface->get_app_info = gtk_app_chooser_button_get_app_info; - iface->refresh = gtk_app_chooser_button_refresh; -} - -static void -gtk_app_chooser_button_activate (GtkAppChooserButton *self) -{ - gtk_widget_activate (self->combobox); -} - -static void -gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass) -{ - GObjectClass *oclass = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - oclass->set_property = gtk_app_chooser_button_set_property; - oclass->get_property = gtk_app_chooser_button_get_property; - oclass->finalize = gtk_app_chooser_button_finalize; - oclass->constructed = gtk_app_chooser_button_constructed; - - widget_class->measure = gtk_app_chooser_button_measure; - widget_class->size_allocate = gtk_app_chooser_button_size_allocate; - widget_class->grab_focus = gtk_widget_grab_focus_child; - widget_class->focus = gtk_widget_focus_child; - - klass->activate = gtk_app_chooser_button_activate; - - g_object_class_override_property (oclass, PROP_CONTENT_TYPE, "content-type"); - - /** - * GtkAppChooserButton:show-dialog-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_dialog_item org.gtk.Property.set=gtk_app_chooser_button_set_show_dialog_item) - * - * Determines whether the dropdown menu shows an item to open - * a `GtkAppChooserDialog`. - */ - properties[PROP_SHOW_DIALOG_ITEM] = - g_param_spec_boolean ("show-dialog-item", NULL, NULL, - FALSE, - G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); - - /** - * GtkAppChooserButton:show-default-item: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_show_default_item org.gtk.Property.set=gtk_app_chooser_button_set_show_default_item) - * - * Determines whether the dropdown menu shows the default application - * on top for the provided content type. - */ - properties[PROP_SHOW_DEFAULT_ITEM] = - g_param_spec_boolean ("show-default-item", NULL, NULL, - FALSE, - G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); - - /** - * GtkAppChooserButton:heading: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_heading org.gtk.Property.set=gtk_app_chooser_button_set_heading) - * - * The text to show at the top of the dialog that can be - * opened from the button. - * - * The string may contain Pango markup. - */ - properties[PROP_HEADING] = - g_param_spec_string ("heading", NULL, NULL, - NULL, - G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); - - /** - * GtkAppChooserButton:modal: (attributes org.gtk.Property.get=gtk_app_chooser_button_get_modal org.gtk.Property.set=gtk_app_chooser_button_set_modal) - * - * Whether the app chooser dialog should be modal. - */ - properties[PROP_MODAL] = - g_param_spec_boolean ("modal", NULL, NULL, - TRUE, - G_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_properties (oclass, NUM_PROPERTIES, properties); - - /** - * GtkAppChooserButton::changed: - * @self: the object which received the signal - * - * Emitted when the active application changes. - */ - signals[SIGNAL_CHANGED] = - g_signal_new (I_("changed"), - G_OBJECT_CLASS_TYPE (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAppChooserButtonClass, changed), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); - - - /** - * GtkAppChooserButton::custom-item-activated: - * @self: the object which received the signal - * @item_name: the name of the activated item - * - * Emitted when a custom item is activated. - * - * Use [method@Gtk.AppChooserButton.append_custom_item], - * to add custom items. - */ - signals[SIGNAL_CUSTOM_ITEM_ACTIVATED] = - g_signal_new (I_("custom-item-activated"), - GTK_TYPE_APP_CHOOSER_BUTTON, - G_SIGNAL_RUN_FIRST | G_SIGNAL_DETAILED, - G_STRUCT_OFFSET (GtkAppChooserButtonClass, custom_item_activated), - NULL, NULL, - NULL, - G_TYPE_NONE, - 1, G_TYPE_STRING); - - /** - * GtkAppChooserButton::activate: - * @widget: the object which received the signal. - * - * Emitted to when the button is activated. - * - * The `::activate` signal on `GtkAppChooserButton` is an action signal and - * emitting it causes the button to pop up its dialog. - * - * Since: 4.4 - */ - signals[ACTIVATE] = - g_signal_new (I_ ("activate"), - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GtkAppChooserButtonClass, activate), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); - - gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE]); - - - gtk_widget_class_set_css_name (widget_class, I_("appchooserbutton")); -} - -static void -gtk_app_chooser_button_init (GtkAppChooserButton *self) -{ - self->modal = TRUE; - - self->custom_item_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - self->store = gtk_list_store_new (NUM_COLUMNS, - G_TYPE_APP_INFO, - G_TYPE_STRING, /* name */ - G_TYPE_STRING, /* label */ - G_TYPE_ICON, - G_TYPE_BOOLEAN, /* separator */ - G_TYPE_BOOLEAN); /* custom */ - self->combobox = gtk_combo_box_new_with_model (GTK_TREE_MODEL (self->store)); - gtk_widget_set_parent (self->combobox, GTK_WIDGET (self)); - - g_signal_connect (self->combobox, "changed", - G_CALLBACK (gtk_app_chooser_button_changed), self); -} - -static gboolean -app_chooser_button_iter_from_custom_name (GtkAppChooserButton *self, - const char *name, - GtkTreeIter *set_me) -{ - GtkTreeIter iter; - char *custom_name = NULL; - - if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->store), &iter)) - return FALSE; - - do { - gtk_tree_model_get (GTK_TREE_MODEL (self->store), &iter, - COLUMN_NAME, &custom_name, - -1); - - if (g_strcmp0 (custom_name, name) == 0) - { - g_free (custom_name); - *set_me = iter; - - return TRUE; - } - - g_free (custom_name); - } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->store), &iter)); - - return FALSE; -} - -static void -real_insert_custom_item (GtkAppChooserButton *self, - const char *name, - const char *label, - GIcon *icon, - gboolean custom, - GtkTreeIter *iter) -{ - if (custom) - { - if (g_hash_table_lookup (self->custom_item_names, name) != NULL) - { - g_warning ("Attempting to add custom item %s to GtkAppChooserButton, " - "when there's already an item with the same name", name); - return; - } - - g_hash_table_insert (self->custom_item_names, - g_strdup (name), GINT_TO_POINTER (1)); - } - - gtk_list_store_set (self->store, iter, - COLUMN_NAME, name, - COLUMN_LABEL, label, - COLUMN_ICON, icon, - COLUMN_CUSTOM, custom, - COLUMN_SEPARATOR, FALSE, - -1); -} - -static void -real_insert_separator (GtkAppChooserButton *self, - gboolean custom, - GtkTreeIter *iter) -{ - gtk_list_store_set (self->store, iter, - COLUMN_CUSTOM, custom, - COLUMN_SEPARATOR, TRUE, - -1); -} - -/** - * gtk_app_chooser_button_new: - * @content_type: the content type to show applications for - * - * Creates a new `GtkAppChooserButton` for applications - * that can handle content of the given type. - * - * Returns: a newly created `GtkAppChooserButton` - */ -GtkWidget * -gtk_app_chooser_button_new (const char *content_type) -{ - g_return_val_if_fail (content_type != NULL, NULL); - - return g_object_new (GTK_TYPE_APP_CHOOSER_BUTTON, - "content-type", content_type, - NULL); -} - -/** - * gtk_app_chooser_button_append_separator: - * @self: a `GtkAppChooserButton` - * - * Appends a separator to the list of applications that is shown - * in the popup. - */ -void -gtk_app_chooser_button_append_separator (GtkAppChooserButton *self) -{ - GtkTreeIter iter; - - g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); - - gtk_list_store_append (self->store, &iter); - real_insert_separator (self, TRUE, &iter); -} - -/** - * gtk_app_chooser_button_append_custom_item: - * @self: a `GtkAppChooserButton` - * @name: the name of the custom item - * @label: the label for the custom item - * @icon: the icon for the custom item - * - * Appends a custom item to the list of applications that is shown - * in the popup. - * - * The item name must be unique per-widget. Clients can use the - * provided name as a detail for the - * [signal@Gtk.AppChooserButton::custom-item-activated] signal, to add a - * callback for the activation of a particular custom item in the list. - * - * See also [method@Gtk.AppChooserButton.append_separator]. - */ -void -gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self, - const char *name, - const char *label, - GIcon *icon) -{ - GtkTreeIter iter; - - g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); - g_return_if_fail (name != NULL); - - gtk_list_store_append (self->store, &iter); - real_insert_custom_item (self, name, label, icon, TRUE, &iter); -} - -/** - * gtk_app_chooser_button_set_active_custom_item: - * @self: a `GtkAppChooserButton` - * @name: the name of the custom item - * - * Selects a custom item. - * - * See [method@Gtk.AppChooserButton.append_custom_item]. - * - * Use [method@Gtk.AppChooser.refresh] to bring the selection - * to its initial state. - */ -void -gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self, - const char *name) -{ - GtkTreeIter iter; - - g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); - g_return_if_fail (name != NULL); - - if (!g_hash_table_contains (self->custom_item_names, name) || - !app_chooser_button_iter_from_custom_name (self, name, &iter)) - { - g_warning ("Can't find the item named %s in the app chooser.", name); - return; - } - - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self->combobox), &iter); -} - -/** - * gtk_app_chooser_button_get_show_dialog_item: (attributes org.gtk.Method.get_property=show-dialog-item) - * @self: a `GtkAppChooserButton` - * - * Returns whether the dropdown menu shows an item - * for a `GtkAppChooserDialog`. - * - * Returns: the value of [property@Gtk.AppChooserButton:show-dialog-item] - */ -gboolean -gtk_app_chooser_button_get_show_dialog_item (GtkAppChooserButton *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE); - - return self->show_dialog_item; -} - -/** - * gtk_app_chooser_button_set_show_dialog_item: (attributes org.gtk.Method.set_property=show-dialog-item) - * @self: a `GtkAppChooserButton` - * @setting: the new value for [property@Gtk.AppChooserButton:show-dialog-item] - * - * Sets whether the dropdown menu of this button should show an - * entry to trigger a `GtkAppChooserDialog`. - */ -void -gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self, - gboolean setting) -{ - if (self->show_dialog_item != setting) - { - self->show_dialog_item = setting; - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DIALOG_ITEM]); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_button_get_show_default_item: (attributes org.gtk.Method.get_property=show-default-item) - * @self: a `GtkAppChooserButton` - * - * Returns whether the dropdown menu should show the default - * application at the top. - * - * Returns: the value of [property@Gtk.AppChooserButton:show-default-item] - */ -gboolean -gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE); - - return self->show_default_item; -} - -/** - * gtk_app_chooser_button_set_show_default_item: (attributes org.gtk.Method.set_property=show-default-item) - * @self: a `GtkAppChooserButton` - * @setting: the new value for [property@Gtk.AppChooserButton:show-default-item] - * - * Sets whether the dropdown menu of this button should show the - * default application for the given content type at top. - */ -void -gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self, - gboolean setting) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); - - if (self->show_default_item != setting) - { - self->show_default_item = setting; - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_DEFAULT_ITEM]); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_button_set_heading: (attributes org.gtk.Method.set_property=heading) - * @self: a `GtkAppChooserButton` - * @heading: a string containing Pango markup - * - * Sets the text to display at the top of the dialog. - * - * If the heading is not set, the dialog displays a default text. - */ -void -gtk_app_chooser_button_set_heading (GtkAppChooserButton *self, - const char *heading) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); - - g_free (self->heading); - self->heading = g_strdup (heading); - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADING]); -} - -/** - * gtk_app_chooser_button_get_heading: (attributes org.gtk.Method.get_property=heading) - * @self: a `GtkAppChooserButton` - * - * Returns the text to display at the top of the dialog. - * - * Returns: (nullable): the text to display at the top of the dialog, - * or %NULL, in which case a default text is displayed - */ -const char * -gtk_app_chooser_button_get_heading (GtkAppChooserButton *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), NULL); - - return self->heading; -} - -/** - * gtk_app_chooser_button_set_modal: (attributes org.gtk.Method.set_property=modal) - * @self: a `GtkAppChooserButton` - * @modal: %TRUE to make the dialog modal - * - * Sets whether the dialog should be modal. - */ -void -gtk_app_chooser_button_set_modal (GtkAppChooserButton *self, - gboolean modal) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self)); - - if (self->modal == modal) - return; - - self->modal = modal; - - g_object_notify (G_OBJECT (self), "modal"); -} - -/** - * gtk_app_chooser_button_get_modal: (attributes org.gtk.Method.get_property=modal) - * @self: a `GtkAppChooserButton` - * - * Gets whether the dialog is modal. - * - * Returns: %TRUE if the dialog is modal - */ -gboolean -gtk_app_chooser_button_get_modal (GtkAppChooserButton *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_BUTTON (self), FALSE); - - return self->modal; -} - diff --git a/gtk/gtkappchooserbutton.h b/gtk/gtkappchooserbutton.h deleted file mode 100644 index 493c5e34d1..0000000000 --- a/gtk/gtkappchooserbutton.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * gtkappchooserbutton.h: an app-chooser button - * - * Copyright (C) 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Cosimo Cecchi - */ - -#ifndef __GTK_APP_CHOOSER_BUTTON_H__ -#define __GTK_APP_CHOOSER_BUTTON_H__ - -#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) -#error "Only can be included directly." -#endif - -#include -#include - -G_BEGIN_DECLS - -#define GTK_TYPE_APP_CHOOSER_BUTTON (gtk_app_chooser_button_get_type ()) -#define GTK_APP_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_BUTTON, GtkAppChooserButton)) -#define GTK_IS_APP_CHOOSER_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_BUTTON)) - -typedef struct _GtkAppChooserButton GtkAppChooserButton; - -GDK_AVAILABLE_IN_ALL -GType gtk_app_chooser_button_get_type (void) G_GNUC_CONST; - -GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_app_chooser_button_new (const char *content_type); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_button_append_separator (GtkAppChooserButton *self); -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_button_append_custom_item (GtkAppChooserButton *self, - const char *name, - const char *label, - GIcon *icon); -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_button_set_active_custom_item (GtkAppChooserButton *self, - const char *name); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_button_set_show_dialog_item (GtkAppChooserButton *self, - gboolean setting); -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_button_get_show_dialog_item (GtkAppChooserButton *self); -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_button_set_heading (GtkAppChooserButton *self, - const char *heading); -GDK_AVAILABLE_IN_ALL -const char * - gtk_app_chooser_button_get_heading (GtkAppChooserButton *self); -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_button_set_show_default_item (GtkAppChooserButton *self, - gboolean setting); -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_button_get_show_default_item (GtkAppChooserButton *self); - -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_button_get_modal (GtkAppChooserButton *self); -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_button_set_modal (GtkAppChooserButton *self, - gboolean modal); - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserButton, g_object_unref) - -G_END_DECLS - -#endif /* __GTK_APP_CHOOSER_BUTTON_H__ */ diff --git a/gtk/gtkappchooserdialog.c b/gtk/gtkappchooserdialog.c deleted file mode 100644 index 3d1669dbf2..0000000000 --- a/gtk/gtkappchooserdialog.c +++ /dev/null @@ -1,787 +0,0 @@ -/* - * gtkappchooserdialog.c: an app-chooser dialog - * - * Copyright (C) 2004 Novell, Inc. - * Copyright (C) 2007, 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Dave Camp - * Alexander Larsson - * Cosimo Cecchi - */ - -/** - * GtkAppChooserDialog: - * - * `GtkAppChooserDialog` shows a `GtkAppChooserWidget` inside a `GtkDialog`. - * - * ![An example GtkAppChooserDialog](appchooserdialog.png) - * - * Note that `GtkAppChooserDialog` does not have any interesting methods - * of its own. Instead, you should get the embedded `GtkAppChooserWidget` - * using [method@Gtk.AppChooserDialog.get_widget] and call its methods if - * the generic [iface@Gtk.AppChooser] interface is not sufficient for - * your needs. - * - * To set the heading that is shown above the `GtkAppChooserWidget`, - * use [method@Gtk.AppChooserDialog.set_heading]. - */ -#include "config.h" - -#include "gtkappchooserdialog.h" - -#include "gtkappchooser.h" -#include "gtkappchooserprivate.h" - -#include "gtkmessagedialog.h" -#include "gtksettings.h" -#include "gtklabel.h" -#include "gtkbox.h" -#include "gtkbutton.h" -#include "gtkentry.h" -#include "gtktogglebutton.h" -#include "gtkheaderbar.h" -#include "gtkdialogprivate.h" -#include "gtksearchbar.h" -#include "gtksizegroup.h" - -#include -#include -#include - -typedef struct _GtkAppChooserDialogClass GtkAppChooserDialogClass; - -struct _GtkAppChooserDialog { - GtkDialog parent; - - char *content_type; - GFile *gfile; - char *heading; - - GtkWidget *label; - GtkWidget *inner_box; - - GtkWidget *open_label; - - GtkWidget *search_bar; - GtkWidget *search_entry; - GtkWidget *app_chooser_widget; - GtkWidget *show_more_button; - GtkWidget *software_button; - - GtkSizeGroup *buttons; - - gboolean show_more_clicked; - gboolean dismissed; -}; - -struct _GtkAppChooserDialogClass { - GtkDialogClass parent_class; -}; - -enum { - PROP_GFILE = 1, - PROP_CONTENT_TYPE, - PROP_HEADING -}; - -static void gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface); -G_DEFINE_TYPE_WITH_CODE (GtkAppChooserDialog, gtk_app_chooser_dialog, GTK_TYPE_DIALOG, - G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER, - gtk_app_chooser_dialog_iface_init)); - - -static void -add_or_find_application (GtkAppChooserDialog *self) -{ - GAppInfo *app; - - app = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self)); - - if (app) - { - /* we don't care about reporting errors here */ - if (self->content_type) - g_app_info_set_as_last_used_for_type (app, - self->content_type, - NULL); - g_object_unref (app); - } -} - -static void -gtk_app_chooser_dialog_response (GtkDialog *dialog, - int response_id, - gpointer user_data) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (dialog); - - switch (response_id) - { - case GTK_RESPONSE_OK: - add_or_find_application (self); - break; - case GTK_RESPONSE_CANCEL: - case GTK_RESPONSE_DELETE_EVENT: - self->dismissed = TRUE; - break; - default: - break; - } -} - -static void -widget_application_selected_cb (GtkAppChooserWidget *widget, - GAppInfo *app_info, - gpointer user_data) -{ - gtk_dialog_set_response_sensitive (GTK_DIALOG (user_data), GTK_RESPONSE_OK, TRUE); -} - -static void -widget_application_activated_cb (GtkAppChooserWidget *widget, - GAppInfo *app_info, - gpointer user_data) -{ - gtk_dialog_response (GTK_DIALOG (user_data), GTK_RESPONSE_OK); -} - -static char * -get_extension (const char *basename) -{ - char *p; - - p = strrchr (basename, '.'); - - if (p && *(p + 1) != '\0') - return g_strdup (p + 1); - - return NULL; -} - -static void -set_dialog_properties (GtkAppChooserDialog *self) -{ - char *name; - char *extension; - char *description; - char *string; - gboolean unknown; - char *title; - char *subtitle; - gboolean use_header; - GtkWidget *header; - - name = NULL; - extension = NULL; - description = NULL; - unknown = TRUE; - - if (self->gfile != NULL) - { - name = g_file_get_basename (self->gfile); - extension = get_extension (name); - } - - if (self->content_type) - { - description = g_content_type_get_description (self->content_type); - unknown = g_content_type_is_unknown (self->content_type); - } - - title = g_strdup (_("Select Application")); - subtitle = NULL; - string = NULL; - - if (name != NULL) - { - /* Translators: %s is a filename */ - subtitle = g_strdup_printf (_("Opening “%s”."), name); - string = g_strdup_printf (_("No applications found for “%s”"), name); - } - else if (self->content_type) - { - /* Translators: %s is a file type description */ - subtitle = g_strdup_printf (_("Opening “%s” files."), - unknown ? self->content_type : description); - string = g_strdup_printf (_("No applications found for “%s” files"), - unknown ? self->content_type : description); - } - - g_object_get (self, "use-header-bar", &use_header, NULL); - if (use_header) - { - GtkWidget *box, *label; - - header = gtk_dialog_get_header_bar (GTK_DIALOG (self)); - - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_valign (box, GTK_ALIGN_CENTER); - - label = gtk_label_new (title); - gtk_widget_set_halign (label, GTK_ALIGN_CENTER); - gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE); - gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); - gtk_label_set_width_chars (GTK_LABEL (label), 5); - gtk_widget_add_css_class (label, "title"); - gtk_widget_set_parent (label, box); - - if (subtitle) - { - label = gtk_label_new (subtitle); - gtk_widget_set_halign (label, GTK_ALIGN_CENTER); - gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE); - gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); - gtk_widget_add_css_class (label, "subtitle"); - gtk_widget_set_parent (label, box); - } - - gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header), box); - } - else - { - gtk_window_set_title (GTK_WINDOW (self), _("Select Application")); - } - - if (self->heading != NULL) - { - gtk_label_set_markup (GTK_LABEL (self->label), self->heading); - gtk_widget_show (self->label); - } - else - { - gtk_widget_hide (self->label); - } - - gtk_app_chooser_widget_set_default_text (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget), - string); - - g_free (title); - g_free (subtitle); - g_free (name); - g_free (extension); - g_free (description); - g_free (string); -} - -static void -show_more_button_clicked_cb (GtkButton *button, - gpointer user_data) -{ - GtkAppChooserDialog *self = user_data; - - g_object_set (self->app_chooser_widget, - "show-recommended", TRUE, - "show-fallback", TRUE, - "show-other", TRUE, - NULL); - - gtk_widget_hide (self->show_more_button); - self->show_more_clicked = TRUE; -} - -static void -widget_notify_for_button_cb (GObject *source, - GParamSpec *pspec, - gpointer user_data) -{ - GtkAppChooserDialog *self = user_data; - GtkAppChooserWidget *widget = GTK_APP_CHOOSER_WIDGET (source); - gboolean should_hide; - - should_hide = gtk_app_chooser_widget_get_show_other (widget) || - self->show_more_clicked; - - if (should_hide) - gtk_widget_hide (self->show_more_button); -} - -static void -construct_appchooser_widget (GtkAppChooserDialog *self) -{ - GAppInfo *info; - - /* Need to build the appchooser widget after, because of the content-type construct-only property */ - self->app_chooser_widget = gtk_app_chooser_widget_new (self->content_type); - gtk_widget_set_vexpand (self->app_chooser_widget, TRUE); - gtk_box_append (GTK_BOX (self->inner_box), self->app_chooser_widget); - - g_signal_connect (self->app_chooser_widget, "application-selected", - G_CALLBACK (widget_application_selected_cb), self); - g_signal_connect (self->app_chooser_widget, "application-activated", - G_CALLBACK (widget_application_activated_cb), self); - g_signal_connect (self->app_chooser_widget, "notify::show-other", - G_CALLBACK (widget_notify_for_button_cb), self); - - /* Add the custom button to the new appchooser */ - gtk_box_append (GTK_BOX (self->inner_box), - self->show_more_button); - - gtk_box_append (GTK_BOX (self->inner_box), - self->software_button); - - info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget)); - gtk_dialog_set_response_sensitive (GTK_DIALOG (self), GTK_RESPONSE_OK, info != NULL); - if (info) - g_object_unref (info); - - _gtk_app_chooser_widget_set_search_entry (GTK_APP_CHOOSER_WIDGET (self->app_chooser_widget), - GTK_EDITABLE (self->search_entry)); - - gtk_search_bar_set_key_capture_widget (GTK_SEARCH_BAR (self->search_bar), - GTK_WIDGET (self)); -} - -static void -set_gfile_and_content_type (GtkAppChooserDialog *self, - GFile *file) -{ - GFileInfo *info; - - if (file == NULL) - return; - - self->gfile = g_object_ref (file); - - info = g_file_query_info (self->gfile, - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, - 0, NULL, NULL); - self->content_type = g_strdup (g_file_info_get_content_type (info)); - - g_object_unref (info); -} - -static GAppInfo * -gtk_app_chooser_dialog_get_app_info (GtkAppChooser *object) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); - - return gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (self->app_chooser_widget)); -} - -static void -gtk_app_chooser_dialog_refresh (GtkAppChooser *object) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self->app_chooser_widget)); -} - -static void -show_error_dialog (const char *primary, - const char *secondary, - GtkWindow *parent) -{ - GtkWidget *message_dialog; - - message_dialog = gtk_message_dialog_new (parent, 0, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - NULL); - g_object_set (message_dialog, - "text", primary, - "secondary-text", secondary, - NULL); - gtk_dialog_set_default_response (GTK_DIALOG (message_dialog), GTK_RESPONSE_OK); - - gtk_widget_show (message_dialog); - - g_signal_connect (message_dialog, "response", - G_CALLBACK (gtk_window_destroy), NULL); -} - -static void -software_button_clicked_cb (GtkButton *button, - GtkAppChooserDialog *self) -{ - GSubprocess *process; - GError *error = NULL; - char *option; - - if (self->content_type) - option = g_strconcat ("--search=", self->content_type, NULL); - else - option = g_strdup ("--mode=overview"); - - process = g_subprocess_new (0, &error, "gnome-software", option, NULL); - if (!process) - { - show_error_dialog (_("Failed to start GNOME Software"), - error->message, GTK_WINDOW (self)); - g_error_free (error); - } - else - g_object_unref (process); - - g_free (option); -} - -static void -ensure_software_button (GtkAppChooserDialog *self) -{ - char *path; - - path = g_find_program_in_path ("gnome-software"); - if (path != NULL) - gtk_widget_show (self->software_button); - else - gtk_widget_hide (self->software_button); - - g_free (path); -} - -static void -setup_search (GtkAppChooserDialog *self) -{ - gboolean use_header; - - g_object_get (self, "use-header-bar", &use_header, NULL); - if (use_header) - { - GtkWidget *button; - GtkWidget *image; - GtkWidget *header; - - button = gtk_toggle_button_new (); - gtk_widget_set_valign (button, GTK_ALIGN_CENTER); - image = gtk_image_new_from_icon_name ("edit-find-symbolic"); - gtk_button_set_child (GTK_BUTTON (button), image); - gtk_widget_add_css_class (button, "image-button"); - gtk_widget_remove_css_class (button, "text-button"); - - header = gtk_dialog_get_header_bar (GTK_DIALOG (self)); - gtk_header_bar_pack_end (GTK_HEADER_BAR (header), button); - gtk_size_group_add_widget (self->buttons, button); - - g_object_bind_property (button, "active", - self->search_bar, "search-mode-enabled", - G_BINDING_BIDIRECTIONAL); - g_object_bind_property (self->search_entry, "sensitive", - button, "sensitive", - G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE); - } -} - -static void -gtk_app_chooser_dialog_constructed (GObject *object) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); - - if (G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed != NULL) - G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->constructed (object); - - construct_appchooser_widget (self); - set_dialog_properties (self); - ensure_software_button (self); - setup_search (self); -} - -static void -gtk_app_chooser_dialog_dispose (GObject *object) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); - - g_clear_object (&self->gfile); - - self->dismissed = TRUE; - - G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->dispose (object); -} - -static void -gtk_app_chooser_dialog_finalize (GObject *object) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); - - g_free (self->content_type); - g_free (self->heading); - - G_OBJECT_CLASS (gtk_app_chooser_dialog_parent_class)->finalize (object); -} - -static void -gtk_app_chooser_dialog_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); - - switch (property_id) - { - case PROP_GFILE: - set_gfile_and_content_type (self, g_value_get_object (value)); - break; - case PROP_CONTENT_TYPE: - /* don't try to override a value previously set with the GFile */ - if (self->content_type == NULL) - self->content_type = g_value_dup_string (value); - break; - case PROP_HEADING: - gtk_app_chooser_dialog_set_heading (self, g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gtk_app_chooser_dialog_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GtkAppChooserDialog *self = GTK_APP_CHOOSER_DIALOG (object); - - switch (property_id) - { - case PROP_GFILE: - if (self->gfile != NULL) - g_value_set_object (value, self->gfile); - break; - case PROP_CONTENT_TYPE: - g_value_set_string (value, self->content_type); - break; - case PROP_HEADING: - g_value_set_string (value, self->heading); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gtk_app_chooser_dialog_iface_init (GtkAppChooserIface *iface) -{ - iface->get_app_info = gtk_app_chooser_dialog_get_app_info; - iface->refresh = gtk_app_chooser_dialog_refresh; -} - -static void -gtk_app_chooser_dialog_class_init (GtkAppChooserDialogClass *klass) -{ - GObjectClass *gobject_class; - GtkWidgetClass *widget_class; - GParamSpec *pspec; - - gobject_class = G_OBJECT_CLASS (klass); - widget_class = GTK_WIDGET_CLASS (klass); - - gobject_class->dispose = gtk_app_chooser_dialog_dispose; - gobject_class->finalize = gtk_app_chooser_dialog_finalize; - gobject_class->set_property = gtk_app_chooser_dialog_set_property; - gobject_class->get_property = gtk_app_chooser_dialog_get_property; - gobject_class->constructed = gtk_app_chooser_dialog_constructed; - - g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type"); - - /** - * GtkAppChooserDialog:gfile: - * - * The GFile used by the `GtkAppChooserDialog`. - * - * The dialog's `GtkAppChooserWidget` content type will - * be guessed from the file, if present. - */ - pspec = g_param_spec_object ("gfile", NULL, NULL, - G_TYPE_FILE, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS); - g_object_class_install_property (gobject_class, PROP_GFILE, pspec); - - /** - * GtkAppChooserDialog:heading: (attributes org.gtk.Property.get=gtk_app_chooser_dialog_get_heading org.gtk.Property.set=gtk_app_chooser_dialog_set_heading) - * - * The text to show at the top of the dialog. - * - * The string may contain Pango markup. - */ - pspec = g_param_spec_string ("heading", NULL, NULL, - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | - G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_property (gobject_class, PROP_HEADING, pspec); - - /* Bind class to template - */ - gtk_widget_class_set_template_from_resource (widget_class, - "/org/gtk/libgtk/ui/gtkappchooserdialog.ui"); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, label); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, show_more_button); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, software_button); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, inner_box); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_bar); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserDialog, search_entry); - gtk_widget_class_bind_template_child(widget_class, GtkAppChooserDialog, buttons); - gtk_widget_class_bind_template_callback (widget_class, show_more_button_clicked_cb); - gtk_widget_class_bind_template_callback (widget_class, software_button_clicked_cb); -} - -static void -gtk_app_chooser_dialog_init (GtkAppChooserDialog *self) -{ - gtk_widget_init_template (GTK_WIDGET (self)); - gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (self)); - - /* we can't override the class signal handler here, as it's a RUN_LAST; - * we want our signal handler instead to be executed before any user code. - */ - g_signal_connect (self, "response", - G_CALLBACK (gtk_app_chooser_dialog_response), NULL); -} - -static void -set_parent_and_flags (GtkWidget *dialog, - GtkWindow *parent, - GtkDialogFlags flags) -{ - if (parent != NULL) - gtk_window_set_transient_for (GTK_WINDOW (dialog), parent); - - if (flags & GTK_DIALOG_MODAL) - gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); - - if (flags & GTK_DIALOG_DESTROY_WITH_PARENT) - gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); -} - -/** - * gtk_app_chooser_dialog_new: - * @parent: (nullable): a `GtkWindow` - * @flags: flags for this dialog - * @file: a `GFile` - * - * Creates a new `GtkAppChooserDialog` for the provided `GFile`. - * - * The dialog will show applications that can open the file. - * - * Returns: a newly created `GtkAppChooserDialog` - */ -GtkWidget * -gtk_app_chooser_dialog_new (GtkWindow *parent, - GtkDialogFlags flags, - GFile *file) -{ - GtkWidget *retval; - - g_return_val_if_fail (G_IS_FILE (file), NULL); - - retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG, - "gfile", file, - NULL); - - set_parent_and_flags (retval, parent, flags); - - return retval; -} - -/** - * gtk_app_chooser_dialog_new_for_content_type: - * @parent: (nullable): a `GtkWindow` - * @flags: flags for this dialog - * @content_type: a content type string - * - * Creates a new `GtkAppChooserDialog` for the provided content type. - * - * The dialog will show applications that can open the content type. - * - * Returns: a newly created `GtkAppChooserDialog` - */ -GtkWidget * -gtk_app_chooser_dialog_new_for_content_type (GtkWindow *parent, - GtkDialogFlags flags, - const char *content_type) -{ - GtkWidget *retval; - - g_return_val_if_fail (content_type != NULL, NULL); - - retval = g_object_new (GTK_TYPE_APP_CHOOSER_DIALOG, - "content-type", content_type, - NULL); - - set_parent_and_flags (retval, parent, flags); - - return retval; -} - -/** - * gtk_app_chooser_dialog_get_widget: - * @self: a `GtkAppChooserDialog` - * - * Returns the `GtkAppChooserWidget` of this dialog. - * - * Returns: (transfer none): the `GtkAppChooserWidget` of @self - */ -GtkWidget * -gtk_app_chooser_dialog_get_widget (GtkAppChooserDialog *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL); - - return self->app_chooser_widget; -} - -/** - * gtk_app_chooser_dialog_set_heading: (attributes org.gtk.Method.set_property=heading) - * @self: a `GtkAppChooserDialog` - * @heading: a string containing Pango markup - * - * Sets the text to display at the top of the dialog. - * - * If the heading is not set, the dialog displays a default text. - */ -void -gtk_app_chooser_dialog_set_heading (GtkAppChooserDialog *self, - const char *heading) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self)); - - g_free (self->heading); - self->heading = g_strdup (heading); - - if (self->label) - { - if (self->heading) - { - gtk_label_set_markup (GTK_LABEL (self->label), self->heading); - gtk_widget_show (self->label); - } - else - { - gtk_widget_hide (self->label); - } - } - - g_object_notify (G_OBJECT (self), "heading"); -} - -/** - * gtk_app_chooser_dialog_get_heading: (attributes org.gtk.Method.get_property=heading) - * @self: a `GtkAppChooserDialog` - * - * Returns the text to display at the top of the dialog. - * - * Returns: (nullable): the text to display at the top of the dialog, - * or %NULL, in which case a default text is displayed - */ -const char * -gtk_app_chooser_dialog_get_heading (GtkAppChooserDialog *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_DIALOG (self), NULL); - - return self->heading; -} diff --git a/gtk/gtkappchooserdialog.h b/gtk/gtkappchooserdialog.h deleted file mode 100644 index 9f3f8c589e..0000000000 --- a/gtk/gtkappchooserdialog.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * gtkappchooserdialog.h: an app-chooser dialog - * - * Copyright (C) 2004 Novell, Inc. - * Copyright (C) 2007, 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Dave Camp - * Alexander Larsson - * Cosimo Cecchi - */ - -#ifndef __GTK_APP_CHOOSER_DIALOG_H__ -#define __GTK_APP_CHOOSER_DIALOG_H__ - -#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) -#error "Only can be included directly." -#endif - -#include -#include - -G_BEGIN_DECLS - -#define GTK_TYPE_APP_CHOOSER_DIALOG (gtk_app_chooser_dialog_get_type ()) -#define GTK_APP_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_DIALOG, GtkAppChooserDialog)) -#define GTK_IS_APP_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_DIALOG)) - -typedef struct _GtkAppChooserDialog GtkAppChooserDialog; - -GDK_AVAILABLE_IN_ALL -GType gtk_app_chooser_dialog_get_type (void) G_GNUC_CONST; - -GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_app_chooser_dialog_new (GtkWindow *parent, - GtkDialogFlags flags, - GFile *file); -GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_app_chooser_dialog_new_for_content_type (GtkWindow *parent, - GtkDialogFlags flags, - const char *content_type); - -GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_app_chooser_dialog_get_widget (GtkAppChooserDialog *self); -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_dialog_set_heading (GtkAppChooserDialog *self, - const char *heading); -GDK_AVAILABLE_IN_ALL -const char * gtk_app_chooser_dialog_get_heading (GtkAppChooserDialog *self); - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserDialog, g_object_unref) - -G_END_DECLS - -#endif /* __GTK_APP_CHOOSER_DIALOG_H__ */ diff --git a/gtk/gtkappchooserprivate.h b/gtk/gtkappchooserprivate.h deleted file mode 100644 index 754619adc7..0000000000 --- a/gtk/gtkappchooserprivate.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * gtkappchooserprivate.h: app-chooser interface - * - * Copyright (C) 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Cosimo Cecchi - */ - -#ifndef __GTK_APP_CHOOSER_PRIVATE_H__ -#define __GTK_APP_CHOOSER_PRIVATE_H__ - -#include -#include - -#include "gtkappchooser.h" -#include "gtkappchooserwidget.h" -#include "gtkentry.h" - -G_BEGIN_DECLS - -typedef struct _GtkAppChooserIface GtkAppChooserIface; -typedef GtkAppChooserIface GtkAppChooserInterface; - -#define GTK_APP_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_APP_CHOOSER, GtkAppChooserIface)) - -struct _GtkAppChooserIface { - GTypeInterface base_iface; - - GAppInfo * (* get_app_info) (GtkAppChooser *object); - void (* refresh) (GtkAppChooser *object); -}; - -void -_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self, - GtkEditable *editable); - - -G_END_DECLS - -#endif /* __GTK_APP_CHOOSER_PRIVATE_H__ */ diff --git a/gtk/gtkappchooserwidget.c b/gtk/gtkappchooserwidget.c deleted file mode 100644 index 90915f06bf..0000000000 --- a/gtk/gtkappchooserwidget.c +++ /dev/null @@ -1,1380 +0,0 @@ -/* - * gtkappchooserwidget.c: an app-chooser widget - * - * Copyright (C) 2004 Novell, Inc. - * Copyright (C) 2007, 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Dave Camp - * Alexander Larsson - * Cosimo Cecchi - */ - -#include "config.h" - -#include "gtkappchooserwidget.h" - -#include "gtkmarshalers.h" -#include "gtkappchooserwidget.h" -#include "gtkappchooserprivate.h" -#include "gtkliststore.h" -#include "gtktreeview.h" -#include "gtktreeselection.h" -#include "gtktreemodelsort.h" -#include "gtkorientable.h" -#include "gtkscrolledwindow.h" -#include "gtklabel.h" -#include "gtkgestureclick.h" -#include "gtkwidgetprivate.h" -#include "gtkprivate.h" - -#include -#include -#include - -/** - * GtkAppChooserWidget: - * - * `GtkAppChooserWidget` is a widget for selecting applications. - * - * It is the main building block for [class@Gtk.AppChooserDialog]. - * Most applications only need to use the latter; but you can use - * this widget as part of a larger widget if you have special needs. - * - * `GtkAppChooserWidget` offers detailed control over what applications - * are shown, using the - * [property@Gtk.AppChooserWidget:show-default], - * [property@Gtk.AppChooserWidget:show-recommended], - * [property@Gtk.AppChooserWidget:show-fallback], - * [property@Gtk.AppChooserWidget:show-other] and - * [property@Gtk.AppChooserWidget:show-all] properties. See the - * [iface@Gtk.AppChooser] documentation for more information about these - * groups of applications. - * - * To keep track of the selected application, use the - * [signal@Gtk.AppChooserWidget::application-selected] and - * [signal@Gtk.AppChooserWidget::application-activated] signals. - * - * # CSS nodes - * - * `GtkAppChooserWidget` has a single CSS node with name appchooser. - */ - -typedef struct _GtkAppChooserWidgetClass GtkAppChooserWidgetClass; - -struct _GtkAppChooserWidget { - GtkWidget parent_instance; - - GAppInfo *selected_app_info; - - GtkWidget *overlay; - - char *content_type; - char *default_text; - - guint show_default : 1; - guint show_recommended : 1; - guint show_fallback : 1; - guint show_other : 1; - guint show_all : 1; - - GtkWidget *program_list; - GtkListStore *program_list_store; - GtkWidget *no_apps_label; - GtkWidget *no_apps; - - GtkTreeViewColumn *column; - GtkCellRenderer *padding_renderer; - GtkCellRenderer *secondary_padding; - - GAppInfoMonitor *monitor; - - GtkWidget *popup_menu; -}; - -struct _GtkAppChooserWidgetClass { - GtkWidgetClass parent_class; - - void (* application_selected) (GtkAppChooserWidget *self, - GAppInfo *app_info); - - void (* application_activated) (GtkAppChooserWidget *self, - GAppInfo *app_info); -}; - -enum { - COLUMN_APP_INFO, - COLUMN_GICON, - COLUMN_NAME, - COLUMN_DESC, - COLUMN_EXEC, - COLUMN_DEFAULT, - COLUMN_HEADING, - COLUMN_HEADING_TEXT, - COLUMN_RECOMMENDED, - COLUMN_FALLBACK, - NUM_COLUMNS -}; - - -enum { - PROP_CONTENT_TYPE = 1, - PROP_GFILE, - PROP_SHOW_DEFAULT, - PROP_SHOW_RECOMMENDED, - PROP_SHOW_FALLBACK, - PROP_SHOW_OTHER, - PROP_SHOW_ALL, - PROP_DEFAULT_TEXT, - N_PROPERTIES -}; - -enum { - SIGNAL_APPLICATION_SELECTED, - SIGNAL_APPLICATION_ACTIVATED, - N_SIGNALS -}; - -static guint signals[N_SIGNALS] = { 0, }; - -static void gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GtkAppChooserWidget, gtk_app_chooser_widget, GTK_TYPE_WIDGET, - G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER, - gtk_app_chooser_widget_iface_init)); - -static void -refresh_and_emit_app_selected (GtkAppChooserWidget *self, - GtkTreeSelection *selection) -{ - GtkTreeModel *model; - GtkTreeIter iter; - GAppInfo *info = NULL; - gboolean should_emit = FALSE; - - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - gtk_tree_model_get (model, &iter, COLUMN_APP_INFO, &info, -1); - - if (info == NULL) - return; - - if (self->selected_app_info) - { - if (!g_app_info_equal (self->selected_app_info, info)) - { - should_emit = TRUE; - g_set_object (&self->selected_app_info, info); - } - } - else - { - should_emit = TRUE; - g_set_object (&self->selected_app_info, info); - } - - g_object_unref (info); - - if (should_emit) - g_signal_emit (self, signals[SIGNAL_APPLICATION_SELECTED], 0, - self->selected_app_info); -} - -static gboolean -path_is_heading (GtkTreeView *view, - GtkTreePath *path) -{ - GtkTreeIter iter; - GtkTreeModel *model; - gboolean res; - - model = gtk_tree_view_get_model (view); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, - COLUMN_HEADING, &res, - -1); - - return res; -} - -static void -program_list_selection_activated (GtkTreeView *view, - GtkTreePath *path, - GtkTreeViewColumn *column, - gpointer user_data) -{ - GtkAppChooserWidget *self = user_data; - GtkTreeSelection *selection; - - if (path_is_heading (view, path)) - return; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list)); - - refresh_and_emit_app_selected (self, selection); - - g_signal_emit (self, signals[SIGNAL_APPLICATION_ACTIVATED], 0, - self->selected_app_info); -} - -static gboolean -gtk_app_chooser_search_equal_func (GtkTreeModel *model, - int column, - const char *key, - GtkTreeIter *iter, - gpointer user_data) -{ - char *name; - char *exec_name; - gboolean ret; - - if (key != NULL) - { - ret = TRUE; - - gtk_tree_model_get (model, iter, - COLUMN_NAME, &name, - COLUMN_EXEC, &exec_name, - -1); - - if ((name != NULL && g_str_match_string (key, name, TRUE)) || - (exec_name != NULL && g_str_match_string (key, exec_name, FALSE))) - ret = FALSE; - - g_free (name); - g_free (exec_name); - - return ret; - } - else - { - return TRUE; - } -} - -static int -gtk_app_chooser_sort_func (GtkTreeModel *model, - GtkTreeIter *a, - GtkTreeIter *b, - gpointer user_data) -{ - gboolean a_recommended, b_recommended; - gboolean a_fallback, b_fallback; - gboolean a_heading, b_heading; - gboolean a_default, b_default; - char *a_name, *b_name, *a_casefold, *b_casefold; - int retval = 0; - - /* this returns: - * - <0 if a should show before b - * - =0 if a is the same as b - * - >0 if a should show after b - */ - - gtk_tree_model_get (model, a, - COLUMN_NAME, &a_name, - COLUMN_RECOMMENDED, &a_recommended, - COLUMN_FALLBACK, &a_fallback, - COLUMN_HEADING, &a_heading, - COLUMN_DEFAULT, &a_default, - -1); - - gtk_tree_model_get (model, b, - COLUMN_NAME, &b_name, - COLUMN_RECOMMENDED, &b_recommended, - COLUMN_FALLBACK, &b_fallback, - COLUMN_HEADING, &b_heading, - COLUMN_DEFAULT, &b_default, - -1); - - /* the default one always wins */ - if (a_default && !b_default) - { - retval = -1; - goto out; - } - - if (b_default && !a_default) - { - retval = 1; - goto out; - } - - /* the recommended one always wins */ - if (a_recommended && !b_recommended) - { - retval = -1; - goto out; - } - - if (b_recommended && !a_recommended) - { - retval = 1; - goto out; - } - - /* the recommended one always wins */ - if (a_fallback && !b_fallback) - { - retval = -1; - goto out; - } - - if (b_fallback && !a_fallback) - { - retval = 1; - goto out; - } - - /* they're both recommended/fallback or not, so if one is a heading, wins */ - if (a_heading) - { - retval = -1; - goto out; - } - - if (b_heading) - { - retval = 1; - goto out; - } - - /* don't order by name recommended applications, but use GLib's ordering */ - if (!a_recommended) - { - a_casefold = a_name != NULL ? - g_utf8_casefold (a_name, -1) : NULL; - b_casefold = b_name != NULL ? - g_utf8_casefold (b_name, -1) : NULL; - - retval = g_strcmp0 (a_casefold, b_casefold); - - g_free (a_casefold); - g_free (b_casefold); - } - - out: - g_free (a_name); - g_free (b_name); - - return retval; -} - -static void -padding_cell_renderer_func (GtkTreeViewColumn *column, - GtkCellRenderer *cell, - GtkTreeModel *model, - GtkTreeIter *iter, - gpointer user_data) -{ - gboolean heading; - - gtk_tree_model_get (model, iter, - COLUMN_HEADING, &heading, - -1); - if (heading) - g_object_set (cell, - "visible", FALSE, - "xpad", 0, - "ypad", 0, - NULL); - else - g_object_set (cell, - "visible", TRUE, - "xpad", 3, - "ypad", 3, - NULL); -} - -static gboolean -gtk_app_chooser_selection_func (GtkTreeSelection *selection, - GtkTreeModel *model, - GtkTreePath *path, - gboolean path_currently_selected, - gpointer user_data) -{ - GtkTreeIter iter; - gboolean heading; - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, - COLUMN_HEADING, &heading, - -1); - - return !heading; -} - -static int -compare_apps_func (gconstpointer a, - gconstpointer b) -{ - return !g_app_info_equal (G_APP_INFO (a), G_APP_INFO (b)); -} - -static gboolean -gtk_app_chooser_widget_add_section (GtkAppChooserWidget *self, - const char *heading_title, - gboolean show_headings, - gboolean recommended, - gboolean fallback, - GList *applications, - GList *exclude_apps) -{ - gboolean heading_added, unref_icon; - GtkTreeIter iter; - GAppInfo *app; - char *app_string, *bold_string; - GIcon *icon; - GList *l; - gboolean retval; - - retval = FALSE; - heading_added = FALSE; - bold_string = g_strdup_printf ("%s", heading_title); - - for (l = applications; l != NULL; l = l->next) - { - app = l->data; - - if (self->content_type != NULL && - !g_app_info_supports_uris (app) && - !g_app_info_supports_files (app)) - continue; - - if (g_list_find_custom (exclude_apps, app, - (GCompareFunc) compare_apps_func)) - continue; - - if (!heading_added && show_headings) - { - gtk_list_store_append (self->program_list_store, &iter); - gtk_list_store_set (self->program_list_store, &iter, - COLUMN_HEADING_TEXT, bold_string, - COLUMN_HEADING, TRUE, - COLUMN_RECOMMENDED, recommended, - COLUMN_FALLBACK, fallback, - -1); - - heading_added = TRUE; - } - - app_string = g_markup_printf_escaped ("%s", - g_app_info_get_name (app) != NULL ? - g_app_info_get_name (app) : ""); - - icon = g_app_info_get_icon (app); - unref_icon = FALSE; - if (icon == NULL) - { - icon = g_themed_icon_new ("application-x-executable"); - unref_icon = TRUE; - } - - gtk_list_store_append (self->program_list_store, &iter); - gtk_list_store_set (self->program_list_store, &iter, - COLUMN_APP_INFO, app, - COLUMN_GICON, icon, - COLUMN_NAME, g_app_info_get_name (app), - COLUMN_DESC, app_string, - COLUMN_EXEC, g_app_info_get_executable (app), - COLUMN_HEADING, FALSE, - COLUMN_RECOMMENDED, recommended, - COLUMN_FALLBACK, fallback, - -1); - - retval = TRUE; - - g_free (app_string); - if (unref_icon) - g_object_unref (icon); - } - - g_free (bold_string); - - return retval; -} - - -static void -gtk_app_chooser_add_default (GtkAppChooserWidget *self, - GAppInfo *app) -{ - GtkTreeIter iter; - GIcon *icon; - char *string; - gboolean unref_icon; - - unref_icon = FALSE; - string = g_strdup_printf ("%s", _("Default Application")); - - gtk_list_store_append (self->program_list_store, &iter); - gtk_list_store_set (self->program_list_store, &iter, - COLUMN_HEADING_TEXT, string, - COLUMN_HEADING, TRUE, - COLUMN_DEFAULT, TRUE, - -1); - - g_free (string); - - string = g_markup_printf_escaped ("%s", - g_app_info_get_name (app) != NULL ? - g_app_info_get_name (app) : ""); - - icon = g_app_info_get_icon (app); - if (icon == NULL) - { - icon = g_themed_icon_new ("application-x-executable"); - unref_icon = TRUE; - } - - gtk_list_store_append (self->program_list_store, &iter); - gtk_list_store_set (self->program_list_store, &iter, - COLUMN_APP_INFO, app, - COLUMN_GICON, icon, - COLUMN_NAME, g_app_info_get_name (app), - COLUMN_DESC, string, - COLUMN_EXEC, g_app_info_get_executable (app), - COLUMN_HEADING, FALSE, - COLUMN_DEFAULT, TRUE, - -1); - - g_free (string); - - if (unref_icon) - g_object_unref (icon); -} - -static void -update_no_applications_label (GtkAppChooserWidget *self) -{ - char *text = NULL, *desc = NULL; - const char *string; - - if (self->default_text == NULL) - { - if (self->content_type) - desc = g_content_type_get_description (self->content_type); - - string = text = g_strdup_printf (_("No applications found for “%s”."), desc); - g_free (desc); - } - else - { - string = self->default_text; - } - - gtk_label_set_text (GTK_LABEL (self->no_apps_label), string); - - g_free (text); -} - -static void -gtk_app_chooser_widget_select_first (GtkAppChooserWidget *self) -{ - GtkTreeIter iter; - GAppInfo *info = NULL; - GtkTreeModel *model; - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list)); - if (!gtk_tree_model_get_iter_first (model, &iter)) - return; - - while (info == NULL) - { - gtk_tree_model_get (model, &iter, - COLUMN_APP_INFO, &info, - -1); - - if (info != NULL) - break; - - if (!gtk_tree_model_iter_next (model, &iter)) - break; - } - - if (info != NULL) - { - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list)); - gtk_tree_selection_select_iter (selection, &iter); - - g_object_unref (info); - } -} - -static void -gtk_app_chooser_widget_real_add_items (GtkAppChooserWidget *self) -{ - GList *all_applications = NULL; - GList *recommended_apps = NULL; - GList *fallback_apps = NULL; - GList *exclude_apps = NULL; - GAppInfo *default_app = NULL; - gboolean show_headings; - gboolean apps_added; - - show_headings = TRUE; - apps_added = FALSE; - - if (self->show_all) - show_headings = FALSE; - - if (self->show_default && self->content_type) - { - default_app = g_app_info_get_default_for_type (self->content_type, FALSE); - - if (default_app != NULL) - { - gtk_app_chooser_add_default (self, default_app); - apps_added = TRUE; - exclude_apps = g_list_prepend (exclude_apps, default_app); - } - } - -#ifndef G_OS_WIN32 - if ((self->content_type && self->show_recommended) || self->show_all) - { - if (self->content_type) - recommended_apps = g_app_info_get_recommended_for_type (self->content_type); - - apps_added |= gtk_app_chooser_widget_add_section (self, _("Recommended Applications"), - show_headings, - !self->show_all, /* mark as recommended */ - FALSE, /* mark as fallback */ - recommended_apps, exclude_apps); - - exclude_apps = g_list_concat (exclude_apps, - g_list_copy (recommended_apps)); - } - - if ((self->content_type && self->show_fallback) || self->show_all) - { - if (self->content_type) - fallback_apps = g_app_info_get_fallback_for_type (self->content_type); - - apps_added |= gtk_app_chooser_widget_add_section (self, _("Related Applications"), - show_headings, - FALSE, /* mark as recommended */ - !self->show_all, /* mark as fallback */ - fallback_apps, exclude_apps); - exclude_apps = g_list_concat (exclude_apps, - g_list_copy (fallback_apps)); - } -#endif - - if (self->show_other || self->show_all) - { - all_applications = g_app_info_get_all (); - - apps_added |= gtk_app_chooser_widget_add_section (self, _("Other Applications"), - show_headings, - FALSE, - FALSE, - all_applications, exclude_apps); - } - - if (!apps_added) - update_no_applications_label (self); - - gtk_widget_set_visible (self->no_apps, !apps_added); - - gtk_app_chooser_widget_select_first (self); - - if (default_app != NULL) - g_object_unref (default_app); - - g_list_free_full (all_applications, g_object_unref); - g_list_free_full (recommended_apps, g_object_unref); - g_list_free_full (fallback_apps, g_object_unref); - g_list_free (exclude_apps); -} - -static void -gtk_app_chooser_widget_initialize_items (GtkAppChooserWidget *self) -{ - /* initial padding */ - g_object_set (self->padding_renderer, - "xpad", self->show_all ? 0 : 6, - NULL); - - /* populate the widget */ - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); -} - -static void -app_info_changed (GAppInfoMonitor *monitor, - GtkAppChooserWidget *self) -{ - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); -} - -static void -gtk_app_chooser_widget_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); - - switch (property_id) - { - case PROP_CONTENT_TYPE: - self->content_type = g_value_dup_string (value); - break; - case PROP_SHOW_DEFAULT: - gtk_app_chooser_widget_set_show_default (self, g_value_get_boolean (value)); - break; - case PROP_SHOW_RECOMMENDED: - gtk_app_chooser_widget_set_show_recommended (self, g_value_get_boolean (value)); - break; - case PROP_SHOW_FALLBACK: - gtk_app_chooser_widget_set_show_fallback (self, g_value_get_boolean (value)); - break; - case PROP_SHOW_OTHER: - gtk_app_chooser_widget_set_show_other (self, g_value_get_boolean (value)); - break; - case PROP_SHOW_ALL: - gtk_app_chooser_widget_set_show_all (self, g_value_get_boolean (value)); - break; - case PROP_DEFAULT_TEXT: - gtk_app_chooser_widget_set_default_text (self, g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gtk_app_chooser_widget_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); - - switch (property_id) - { - case PROP_CONTENT_TYPE: - g_value_set_string (value, self->content_type); - break; - case PROP_SHOW_DEFAULT: - g_value_set_boolean (value, self->show_default); - break; - case PROP_SHOW_RECOMMENDED: - g_value_set_boolean (value, self->show_recommended); - break; - case PROP_SHOW_FALLBACK: - g_value_set_boolean (value, self->show_fallback); - break; - case PROP_SHOW_OTHER: - g_value_set_boolean (value, self->show_other); - break; - case PROP_SHOW_ALL: - g_value_set_boolean (value, self->show_all); - break; - case PROP_DEFAULT_TEXT: - g_value_set_string (value, self->default_text); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -gtk_app_chooser_widget_constructed (GObject *object) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); - - if (G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed != NULL) - G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->constructed (object); - - gtk_app_chooser_widget_initialize_items (self); -} - -static void -gtk_app_chooser_widget_finalize (GObject *object) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); - - g_free (self->content_type); - g_free (self->default_text); - g_signal_handlers_disconnect_by_func (self->monitor, app_info_changed, self); - g_object_unref (self->monitor); - - G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->finalize (object); -} - -static void -gtk_app_chooser_widget_dispose (GObject *object) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); - - g_clear_object (&self->selected_app_info); - - if (self->overlay) - { - gtk_widget_unparent (self->overlay); - self->overlay = NULL; - } - - G_OBJECT_CLASS (gtk_app_chooser_widget_parent_class)->dispose (object); -} - -static void -gtk_app_chooser_widget_measure (GtkWidget *widget, - GtkOrientation orientation, - int for_size, - int *minimum, - int *natural, - int *minimum_baseline, - int *natural_baseline) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget); - - gtk_widget_measure (self->overlay, orientation, for_size, - minimum, natural, - minimum_baseline, natural_baseline); -} - -static void -gtk_app_chooser_widget_snapshot (GtkWidget *widget, - GtkSnapshot *snapshot) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget); - - gtk_widget_snapshot_child (widget, self->overlay, snapshot); -} - -static void -gtk_app_chooser_widget_size_allocate (GtkWidget *widget, - int width, - int height, - int baseline) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (widget); - - GTK_WIDGET_CLASS (gtk_app_chooser_widget_parent_class)->size_allocate (widget, width, height, baseline); - - gtk_widget_size_allocate (self->overlay, - &(GtkAllocation) { - 0, 0, - width, height - },baseline); -} - -static void -gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass) -{ - GtkWidgetClass *widget_class; - GObjectClass *gobject_class; - GParamSpec *pspec; - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = gtk_app_chooser_widget_dispose; - gobject_class->finalize = gtk_app_chooser_widget_finalize; - gobject_class->set_property = gtk_app_chooser_widget_set_property; - gobject_class->get_property = gtk_app_chooser_widget_get_property; - gobject_class->constructed = gtk_app_chooser_widget_constructed; - - widget_class = GTK_WIDGET_CLASS (klass); - widget_class->measure = gtk_app_chooser_widget_measure; - widget_class->size_allocate = gtk_app_chooser_widget_size_allocate; - widget_class->snapshot = gtk_app_chooser_widget_snapshot; - - g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type"); - - /** - * GtkAppChooserWidget:show-default: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_default org.gtk.Property.set=gtk_app_chooser_widget_set_show_default) - * - * Determines whether the app chooser should show the default - * handler for the content type in a separate section. - * - * If %FALSE, the default handler is listed among the recommended - * applications. - */ - pspec = g_param_spec_boolean ("show-default", NULL, NULL, - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_property (gobject_class, PROP_SHOW_DEFAULT, pspec); - - /** - * GtkAppChooserWidget:show-recommended: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_recommended org.gtk.Property.set=gtk_app_chooser_widget_set_show_recommended) - * - * Determines whether the app chooser should show a section - * for recommended applications. - * - * If %FALSE, the recommended applications are listed - * among the other applications. - */ - pspec = g_param_spec_boolean ("show-recommended", NULL, NULL, - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_property (gobject_class, PROP_SHOW_RECOMMENDED, pspec); - - /** - * GtkAppChooserWidget:show-fallback: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_fallback org.gtk.Property.set=gtk_app_chooser_widget_set_show_fallback) - * - * Determines whether the app chooser should show a section - * for fallback applications. - * - * If %FALSE, the fallback applications are listed among the - * other applications. - */ - pspec = g_param_spec_boolean ("show-fallback", NULL, NULL, - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_property (gobject_class, PROP_SHOW_FALLBACK, pspec); - - /** - * GtkAppChooserWidget:show-other: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_other org.gtk.Property.set=gtk_app_chooser_widget_set_show_other) - * - * Determines whether the app chooser should show a section - * for other applications. - */ - pspec = g_param_spec_boolean ("show-other", NULL, NULL, - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_property (gobject_class, PROP_SHOW_OTHER, pspec); - - /** - * GtkAppChooserWidget:show-all: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_show_all org.gtk.Property.set=gtk_app_chooser_widget_set_show_all) - * - * If %TRUE, the app chooser presents all applications - * in a single list, without subsections for default, - * recommended or related applications. - */ - pspec = g_param_spec_boolean ("show-all", NULL, NULL, - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_property (gobject_class, PROP_SHOW_ALL, pspec); - - /** - * GtkAppChooserWidget:default-text: (attributes org.gtk.Property.get=gtk_app_chooser_widget_get_default_text org.gtk.Property.set=gtk_app_chooser_widget_set_default_text) - * - * The text that appears in the widget when there are no applications - * for the given content type. - */ - pspec = g_param_spec_string ("default-text", NULL, NULL, - NULL, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - g_object_class_install_property (gobject_class, PROP_DEFAULT_TEXT, pspec); - - /** - * GtkAppChooserWidget::application-selected: - * @self: the object which received the signal - * @application: the selected `GAppInfo` - * - * Emitted when an application item is selected from the widget's list. - */ - signals[SIGNAL_APPLICATION_SELECTED] = - g_signal_new (I_("application-selected"), - GTK_TYPE_APP_CHOOSER_WIDGET, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_selected), - NULL, NULL, - NULL, - G_TYPE_NONE, - 1, G_TYPE_APP_INFO); - - /** - * GtkAppChooserWidget::application-activated: - * @self: the object which received the signal - * @application: the activated `GAppInfo` - * - * Emitted when an application item is activated from the widget's list. - * - * This usually happens when the user double clicks an item, or an item - * is selected and the user presses one of the keys Space, Shift+Space, - * Return or Enter. - */ - signals[SIGNAL_APPLICATION_ACTIVATED] = - g_signal_new (I_("application-activated"), - GTK_TYPE_APP_CHOOSER_WIDGET, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkAppChooserWidgetClass, application_activated), - NULL, NULL, - NULL, - G_TYPE_NONE, - 1, G_TYPE_APP_INFO); - - /* Bind class to template - */ - gtk_widget_class_set_template_from_resource (widget_class, - "/org/gtk/libgtk/ui/gtkappchooserwidget.ui"); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, program_list_store); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, column); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, padding_renderer); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, secondary_padding); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps_label); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, no_apps); - gtk_widget_class_bind_template_child (widget_class, GtkAppChooserWidget, overlay); - gtk_widget_class_bind_template_callback (widget_class, refresh_and_emit_app_selected); - gtk_widget_class_bind_template_callback (widget_class, program_list_selection_activated); - - gtk_widget_class_set_css_name (widget_class, I_("appchooser")); -} - -static void -gtk_app_chooser_widget_init (GtkAppChooserWidget *self) -{ - GtkTreeSelection *selection; - GtkTreeModel *sort; - - gtk_widget_init_template (GTK_WIDGET (self)); - - /* Various parts of the GtkTreeView code need custom code to setup, mostly - * because we lack signals to connect to, or properties to set. - */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->program_list)); - gtk_tree_selection_set_select_function (selection, gtk_app_chooser_selection_func, - self, NULL); - - sort = gtk_tree_view_get_model (GTK_TREE_VIEW (self->program_list)); - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), - COLUMN_NAME, - GTK_SORT_ASCENDING); - gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort), - COLUMN_NAME, - gtk_app_chooser_sort_func, - self, NULL); - - gtk_tree_view_set_search_column (GTK_TREE_VIEW (self->program_list), COLUMN_NAME); - gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (self->program_list), - gtk_app_chooser_search_equal_func, - NULL, NULL); - - gtk_tree_view_column_set_cell_data_func (self->column, - self->secondary_padding, - padding_cell_renderer_func, - NULL, NULL); - - self->monitor = g_app_info_monitor_get (); - g_signal_connect (self->monitor, "changed", - G_CALLBACK (app_info_changed), self); -} - -static GAppInfo * -gtk_app_chooser_widget_get_app_info (GtkAppChooser *object) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); - - if (self->selected_app_info == NULL) - return NULL; - - return g_object_ref (self->selected_app_info); -} - -static void -gtk_app_chooser_widget_refresh (GtkAppChooser *object) -{ - GtkAppChooserWidget *self = GTK_APP_CHOOSER_WIDGET (object); - - if (self->program_list_store != NULL) - { - gtk_list_store_clear (self->program_list_store); - - /* don't add additional xpad if we don't have headings */ - g_object_set (self->padding_renderer, - "visible", !self->show_all, - NULL); - - gtk_app_chooser_widget_real_add_items (self); - } -} - -static void -gtk_app_chooser_widget_iface_init (GtkAppChooserIface *iface) -{ - iface->get_app_info = gtk_app_chooser_widget_get_app_info; - iface->refresh = gtk_app_chooser_widget_refresh; -} - -/** - * gtk_app_chooser_widget_new: - * @content_type: the content type to show applications for - * - * Creates a new `GtkAppChooserWidget` for applications - * that can handle content of the given type. - * - * Returns: a newly created `GtkAppChooserWidget` - */ -GtkWidget * -gtk_app_chooser_widget_new (const char *content_type) -{ - return g_object_new (GTK_TYPE_APP_CHOOSER_WIDGET, - "content-type", content_type, - NULL); -} - -/** - * gtk_app_chooser_widget_set_show_default: (attributes org.gtk.Method.set_property=show-default) - * @self: a `GtkAppChooserWidget` - * @setting: the new value for [property@Gtk.AppChooserWidget:show-default] - * - * Sets whether the app chooser should show the default handler - * for the content type in a separate section. - */ -void -gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self, - gboolean setting) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); - - if (self->show_default != setting) - { - self->show_default = setting; - - g_object_notify (G_OBJECT (self), "show-default"); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_widget_get_show_default: (attributes org.gtk.Method.get_property=show-default) - * @self: a `GtkAppChooserWidget` - * - * Gets whether the app chooser should show the default handler - * for the content type in a separate section. - * - * Returns: the value of [property@Gtk.AppChooserWidget:show-default] - */ -gboolean -gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); - - return self->show_default; -} - -/** - * gtk_app_chooser_widget_set_show_recommended: (attributes org.gtk.Method.set_property=show-recommended) - * @self: a `GtkAppChooserWidget` - * @setting: the new value for [property@Gtk.AppChooserWidget:show-recommended] - * - * Sets whether the app chooser should show recommended applications - * for the content type in a separate section. - */ -void -gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self, - gboolean setting) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); - - if (self->show_recommended != setting) - { - self->show_recommended = setting; - - g_object_notify (G_OBJECT (self), "show-recommended"); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_widget_get_show_recommended: (attributes org.gtk.Method.get_property=show-recommended) - * @self: a `GtkAppChooserWidget` - * - * Gets whether the app chooser should show recommended applications - * for the content type in a separate section. - * - * Returns: the value of [property@Gtk.AppChooserWidget:show-recommended] - */ -gboolean -gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); - - return self->show_recommended; -} - -/** - * gtk_app_chooser_widget_set_show_fallback: (attributes org.gtk.Method.set_property=show-fallback) - * @self: a `GtkAppChooserWidget` - * @setting: the new value for [property@Gtk.AppChooserWidget:show-fallback] - * - * Sets whether the app chooser should show related applications - * for the content type in a separate section. - */ -void -gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self, - gboolean setting) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); - - if (self->show_fallback != setting) - { - self->show_fallback = setting; - - g_object_notify (G_OBJECT (self), "show-fallback"); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_widget_get_show_fallback: (attributes org.gtk.Method.get_property=show-fallback) - * @self: a `GtkAppChooserWidget` - * - * Gets whether the app chooser should show related applications - * for the content type in a separate section. - * - * Returns: the value of [property@Gtk.AppChooserWidget:show-fallback] - */ -gboolean -gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); - - return self->show_fallback; -} - -/** - * gtk_app_chooser_widget_set_show_other: (attributes org.gtk.Method.set_property=show-other) - * @self: a `GtkAppChooserWidget` - * @setting: the new value for [property@Gtk.AppChooserWidget:show-other] - * - * Sets whether the app chooser should show applications - * which are unrelated to the content type. - */ -void -gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self, - gboolean setting) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); - - if (self->show_other != setting) - { - self->show_other = setting; - - g_object_notify (G_OBJECT (self), "show-other"); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_widget_get_show_other: (attributes org.gtk.Method.get_property=show-other) - * @self: a `GtkAppChooserWidget` - * - * Gets whether the app chooser should show applications - * which are unrelated to the content type. - * - * Returns: the value of [property@Gtk.AppChooserWidget:show-other] - */ -gboolean -gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); - - return self->show_other; -} - -/** - * gtk_app_chooser_widget_set_show_all: (attributes org.gtk.Method.set_property=show-all) - * @self: a `GtkAppChooserWidget` - * @setting: the new value for [property@Gtk.AppChooserWidget:show-all] - * - * Sets whether the app chooser should show all applications - * in a flat list. - */ -void -gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self, - gboolean setting) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); - - if (self->show_all != setting) - { - self->show_all = setting; - - g_object_notify (G_OBJECT (self), "show-all"); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_widget_get_show_all: (attributes org.gtk.Method.get_property=show-all) - * @self: a `GtkAppChooserWidget` - * - * Gets whether the app chooser should show all applications - * in a flat list. - * - * Returns: the value of [property@Gtk.AppChooserWidget:show-all] - */ -gboolean -gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), FALSE); - - return self->show_all; -} - -/** - * gtk_app_chooser_widget_set_default_text: (attributes org.gtk.Method.set_property=default-text) - * @self: a `GtkAppChooserWidget` - * @text: the new value for [property@Gtk.AppChooserWidget:default-text] - * - * Sets the text that is shown if there are not applications - * that can handle the content type. - */ -void -gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self, - const char *text) -{ - g_return_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self)); - - if (g_strcmp0 (text, self->default_text) != 0) - { - g_free (self->default_text); - self->default_text = g_strdup (text); - - g_object_notify (G_OBJECT (self), "default-text"); - - gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); - } -} - -/** - * gtk_app_chooser_widget_get_default_text: (attributes org.gtk.Method.get_property=default-text) - * @self: a `GtkAppChooserWidget` - * - * Returns the text that is shown if there are not applications - * that can handle the content type. - * - * Returns: (nullable): the value of [property@Gtk.AppChooserWidget:default-text] - */ -const char * -gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self) -{ - g_return_val_if_fail (GTK_IS_APP_CHOOSER_WIDGET (self), NULL); - - return self->default_text; -} - -void -_gtk_app_chooser_widget_set_search_entry (GtkAppChooserWidget *self, - GtkEditable *entry) -{ - gtk_tree_view_set_search_entry (GTK_TREE_VIEW (self->program_list), entry); - - g_object_bind_property (self->no_apps, "visible", - entry, "sensitive", - G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN); -} diff --git a/gtk/gtkappchooserwidget.h b/gtk/gtkappchooserwidget.h deleted file mode 100644 index 6167e05739..0000000000 --- a/gtk/gtkappchooserwidget.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * gtkappchooserwidget.h: an app-chooser widget - * - * Copyright (C) 2004 Novell, Inc. - * Copyright (C) 2007, 2010 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library. If not, see . - * - * Authors: Dave Camp - * Alexander Larsson - * Cosimo Cecchi - */ - -#ifndef __GTK_APP_CHOOSER_WIDGET_H__ -#define __GTK_APP_CHOOSER_WIDGET_H__ - -#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) -#error "Only can be included directly." -#endif - -#include -#include - -G_BEGIN_DECLS - -#define GTK_TYPE_APP_CHOOSER_WIDGET (gtk_app_chooser_widget_get_type ()) -#define GTK_APP_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_APP_CHOOSER_WIDGET, GtkAppChooserWidget)) -#define GTK_IS_APP_CHOOSER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_APP_CHOOSER_WIDGET)) - -typedef struct _GtkAppChooserWidget GtkAppChooserWidget; - -GDK_AVAILABLE_IN_ALL -GType gtk_app_chooser_widget_get_type (void) G_GNUC_CONST; - -GDK_AVAILABLE_IN_ALL -GtkWidget * gtk_app_chooser_widget_new (const char *content_type); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_widget_set_show_default (GtkAppChooserWidget *self, - gboolean setting); -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_widget_get_show_default (GtkAppChooserWidget *self); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_widget_set_show_recommended (GtkAppChooserWidget *self, - gboolean setting); -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_widget_get_show_recommended (GtkAppChooserWidget *self); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_widget_set_show_fallback (GtkAppChooserWidget *self, - gboolean setting); -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_widget_get_show_fallback (GtkAppChooserWidget *self); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_widget_set_show_other (GtkAppChooserWidget *self, - gboolean setting); -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_widget_get_show_other (GtkAppChooserWidget *self); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_widget_set_show_all (GtkAppChooserWidget *self, - gboolean setting); -GDK_AVAILABLE_IN_ALL -gboolean gtk_app_chooser_widget_get_show_all (GtkAppChooserWidget *self); - -GDK_AVAILABLE_IN_ALL -void gtk_app_chooser_widget_set_default_text (GtkAppChooserWidget *self, - const char *text); -GDK_AVAILABLE_IN_ALL -const char * gtk_app_chooser_widget_get_default_text (GtkAppChooserWidget *self); - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkAppChooserWidget, g_object_unref) - -G_END_DECLS - -#endif /* __GTK_APP_CHOOSER_WIDGET_H__ */ diff --git a/gtk/meson.build b/gtk/meson.build index 9982cc1678..46a50717bf 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -159,10 +159,6 @@ gtk_public_sources = files([ 'gtkactionable.c', 'gtkactionbar.c', 'gtkadjustment.c', - 'gtkappchooser.c', - 'gtkappchooserbutton.c', - 'gtkappchooserdialog.c', - 'gtkappchooserwidget.c', 'gtkapplication.c', 'gtkapplicationwindow.c', 'gtkaspectframe.c', @@ -451,10 +447,6 @@ gtk_public_headers = files([ 'gtkactionable.h', 'gtkactionbar.h', 'gtkadjustment.h', - 'gtkappchooser.h', - 'gtkappchooserbutton.h', - 'gtkappchooserdialog.h', - 'gtkappchooserwidget.h', 'gtkapplication.h', 'gtkapplicationwindow.h', 'gtkaspectframe.h', @@ -704,6 +696,7 @@ gtk_public_headers = files([ ]) install_headers(gtk_public_headers, subdir: 'gtk-4.0/gtk/') +install_headers(gtk_deprecated_headers, subdir: 'gtk-4.0/gtk/deprecated') gtk_sources = gtk_public_sources + gtk_private_sources diff --git a/tests/testappchooser.c b/tests/testappchooser.c index a3418dd34b..09a856d561 100644 --- a/tests/testappchooser.c +++ b/tests/testappchooser.c @@ -21,6 +21,8 @@ #include #include +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + static GtkWidget *toplevel; static GFile *file; static GtkWidget *grid, *file_l, *open; diff --git a/tests/testappchooserbutton.c b/tests/testappchooserbutton.c index 9024b51dfa..1ffc062d4a 100644 --- a/tests/testappchooserbutton.c +++ b/tests/testappchooserbutton.c @@ -21,6 +21,8 @@ #include #include +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + #define CUSTOM_ITEM "custom-item" static GtkWidget *toplevel, *button, *box; diff --git a/testsuite/gtk/templates.c b/testsuite/gtk/templates.c index 5911882198..b2a549942d 100644 --- a/testsuite/gtk/templates.c +++ b/testsuite/gtk/templates.c @@ -198,6 +198,8 @@ test_action_bar_basic (void) g_object_unref (g_object_ref_sink (widget)); } +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + static void test_app_chooser_widget_basic (void) { @@ -227,6 +229,8 @@ test_app_chooser_dialog_basic (void) gtk_window_destroy (GTK_WINDOW (widget)); } +G_GNUC_END_IGNORE_DEPRECATIONS + static void test_color_chooser_dialog_basic (void) {